Skip to content

Sixth History polish: Librarian hierarchy, Focus/CLI restyle, full identity sweep - #27

Merged
aaroncoville merged 69 commits into
theme/sixth-historyfrom
theme/sixth-history-polish
Sep 25, 2026
Merged

aaroncoville merged 69 commits into
theme/sixth-historyfrom
theme/sixth-history-polish

Conversation

@aaroncoville

Copy link
Copy Markdown
Owner

Finishes the Sixth History identity pass (extends the M1 chrome work). Two atomic commits on 830faa32.

What changed

  • Librarian hierarchy reworked: the tan-on-brown surfaces move to an ink/aubergine hierarchy. Final raised-surface contrast ratios: primary 10.95:1, secondary 7.80:1, tertiary 4.55:1, gilt 5.94:1, UI boundary 3.04:1 (all AA-clean).
  • Focus mode + CLI restyled in the occult treatment; the Focus label now reads SIXTH HISTORY.
  • Identity sweep: renderer/splash/window identity, Sixth logo in the upper-left and orchestrator surfaces, remaining Munder Difflin/Michael assets replaced with the House mark (uncropped square), packaged PNG/ICO/ICNS icons regenerated and validated.

Verification

Focused affected suite 57/57; broader affected 74 pass / 1 skip; typecheck, build, diff-check all pass. Full npm run test:focused: 1446 pass / 44 fail — every failure is the documented sandbox EPERM on home writes/socket binds, not a product assertion.

Review note

No before/after screenshots are attached: the implementing sandbox cannot launch Electron, and running against live userData was out of bounds. The look is best reviewed by checking out the branch and running npm run dev — the changes are visible on the first screen (splash, chrome, dock icon).

Changes stay within the theme/skin layer to keep upstream rebases cheap.

wall-sync and others added 30 commits September 9, 2026 10:09
v0.5.2 is out and munderdiffl.in was the only thing still saying 0.4.6.

- structured data: softwareVersion 0.4.6 -> 0.5.2, which is what search
  engines read.
- the download script's REL fallback 0.4.6 -> 0.5.2. Only used when the
  GitHub API call fails; the live links already resolved to 0.5.2 on their
  own, so the download buttons were never wrong.
- the languages section's "NEW IN 0.4.6" kicker becomes "LANGUAGES".
  Languages shipped IN 0.4.6, so bumping the number would have made the
  sentence false, and two releases on the feature is not new either. Every
  other kicker on this page is a plain topic label with no version, so this
  one stops carrying a version that has to be maintained.
- a CSS comment that carried the version for no reason.

Also removes the Razorpay checkout, which was still live on this page:
"Claim your plaque" linked straight to it, and PAY_URL was reachable from
the download modal through goPay(). The wall is our thank you page
(founder, 9 Sep 2026) and a thank you page does not have a checkout on it.
goPay() now opens the wall to be read. The strip's copy goes past tense
with it, because a price and terms with no button advertises something
that cannot be bought.

The wall page itself is not in this commit.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRHj1JncRch8N1D7uP5r7o
Replaces docs/index.html with the landing we built for 0.5.2, on the
founder's direct instruction. One file: fonts, logo and the video poster
are inlined, so it needs no build step and no external stylesheet.

Adds the two media files it uses: pro-stapler.mp4 (the PRO recording) and
stapler-settings.png.

Three ./media references are deliberately absent — pro-stapler.gif,
stapler-note.png and stapler-transcript.png. They are DROP SLOTS, not
broken images: each slot hides its <img> until the browser confirms a
decode and shows a hand-drawn panel in the page's own style meanwhile,
and the PRO slot additionally falls back to data-mp4. Verified by
rendering: zero broken-image icons on the page. Drop a real file beside
the page and its slot upgrades itself with no markup change.

Carries the anonymous analytics with the corrected privacy posture:
person profiles never, autocapture off, session recording off, DNT
honoured, and before_send nulling $ip with the GeoIP lookup disabled,
which is what docs/privacy.html promises readers.

Downloads: the three plain buttons point at harnessmd.com/download, which
reads the release channel. The script's BASE stays on the artifact
directory because it is concatenated with a filename and
harnessmd.com/download/<file> is a 404.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRHj1JncRch8N1D7uP5r7o
Six figures in the strip, fixed by the founder: 100K+ downloads, 6.7K
stars, #1 GitHub Trending, #5 Product Hunt, 1M+ Reddit views, 5M+
Instagram and X. The two telemetry chips that were there (116K agent
runs, 12K installs) are folded into the single downloads figure, and
"MIT licensed" is dropped rather than reworded.

The GitHub Trending and Product Hunt badges return to the hero, centered
directly above the title, carried over from the previous landing page.
Trendshift's raster is rebuilt in this page's tokens because the shipped
one is purple on white; Product Hunt's is their own asset and still reads
"#5 Product of the Day", checked today.

The star count was hardcoded 6.5K in three places with no fetch anywhere
on the page. All three now say 6.7K (GitHub API, 6,686 today) and share a
.starct class that a fetch overwrites when a real number comes back. The
unauthenticated API allows 60 requests an hour per IP, so a share of
visitors will be rate limited; every failure path returns silently and
leaves the written number, so nobody sees a spinner, a dash or a zero.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRHj1JncRch8N1D7uP5r7o
Founder's pick, by position in the two rows of controls: the fifth
expression chip (Surprised) and the fourth colour dot (Blue, fourth of
the six pastels, which paint first). Was happy and yellow.

Written as STAPLER_EXPRESSION and STAPLER_COLOR, and deliberately not by
repointing PUCK_DEFAULT_COLOR: that constant is also the yellow swatch's
own hex, so aiming it at blue would leave the palette with two blues and
no yellow.

Applied in both places Stapler sits at rest, the customiser disc and the
Pro feature card, so the same character is not two different colours on
one page. Confirmed by running the page's own script in a DOM stub:
expression 5 of 14 selected, colour 4 of 6 in the pastel row selected,
nothing selected in the vibrant row.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRHj1JncRch8N1D7uP5r7o
The founder reversed his older standing rule that the page shows monthly,
starting-from, and never leads with an annual total. The annual plan is the
default now, including where people pay, so the year is the headline figure
on Pro and the month is the alternative underneath.

Four visitor-facing places, not the three that were expected:
  - the Pro tier card, now $200 struck through then $150 a year, with
    "or $20 a month" beneath it
  - the Pro call to action beside Stapler, "Get Pro, $20 a month" becomes
    "Get Pro, $150 a year". This one was not on the list and still led with
    the month, so it would have contradicted the new rule on the same page.
  - the "What does it cost?" answer in the FAQ
  - the pricing section comment, which now records the reversal and the three
    figures behind it, so the next reader does not restore the old rule

The three line numbers the change was described against (a plan-price span, a
sandbox option, and a price rebuilt in calculator JS) are not in this file.
They belong to the landing page that bcb7480 replaced. This page is 1,126
lines, prints no sandbox price at all, and rebuilds no price at runtime, so
nothing here regenerates the old number after a click.

Figures verified in web/harnessmd/src/server/pricing.ts: individual 2000 is
$20 a month, individualAnnual 20000 is the $200 list, individualAnnualLaunch
15000 is the $150 launch price. The saving is shown as two figures and a
strikethrough rather than as a percentage, which is what that file asks for.

Untouched on purpose: every Teams figure, and the Teams card still leads with
the month. That was named as out of scope, so the reversal has not been
applied there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LRHj1JncRch8N1D7uP5r7o
The ten most visited evergreen posts described releases from 0.3.1 to
0.4.6, an orchestrator the product no longer calls GOD, ten engines
instead of twelve, and competitors that have since changed. Each one is
now current with Munder Difflin 0.5.2 and today's positioning, checked
on 10 September 2026.

Rewritten: your-first-hour-with-munder-difflin, run-munder-difflin-on-open-models,
run-munder-difflin-on-a-mac-mini, deploy-a-blog-writer-agent,
command-center-guide, how-to-hire-from-the-agent-gallery,
what-is-a-multi-agent-harness, best-claude-code-multi-agent-tools,
qm-vs-munder-difflin. Updated in place: how-to-install-and-use-munder-difflin.

Product facts were checked against the 0.5.2 release and its assets, the
source at the v0.5.2 tag, the site, and the app's own strings. Facts about
other tools come from their own sites, READMEs and docs. New prose has no
dashes. Slugs, primary keywords and images are unchanged. The regenerated
pages under docs/blog are only the ten posts plus the cards, tag pages,
topic pages, index and feed that show their titles and descriptions.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
Search Console verifies https://munderdiffl.in/ as a URL prefix property by
fetching this file from the site root. It has to stay in place after
verification succeeds, or the property drops back to unverified.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
…json

The Typecheck job has failed on every PR since the 0.5.2 landing page.
docs/index.html points its direct downloads at 0.5.2 on app.harnessmd.com
while package.json on main is still 0.4.6, and rule 3 demanded an exact
match.

Rule 3 now fails only when the site fallback is older than package.json.
--live also HEADs the three site download files, so a newer version whose
files do not exist still gets caught.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
The index featured whatever post was newest. At four posts every four hours
that changes all day, so the guides Google already sends readers to would
slide off the top. Posts with `pinned: true` now sit in a "Start here" row on
the index, in `pinOrder`, and first on their topic page, with a Pinned chip.

Pinned: your first hour, install guide, open models, managing many Claude Code
sessions, best multi agent tools, what a multi agent harness is. The list comes
from Ryan's PostHog numbers in the blog baseline. docs/blog is left to the
Build blog workflow, which rebuilds it on merge.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
A release post for 0.5.2: Community builds are no longer signed or
notarized and the Pro build is the one we sign and maintain, how to
install 0.5.2, what Pro is and adds (the Stapler included), how to
start Pro, what each version from 0.4.7 to 0.5.2 changed, and credits
for the outside contributors whose pull requests shipped in 0.5.0.

The v0.4.6 post gets a one line link to the newer release. Facts come
from CHANGELOG.md and the locale strings on pro/v052, the v0.5.2 GitHub
release, and the live download and pricing pages.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
main requires status checks, so pushes from Actions are rejected (GH006).
Build blog now checks that a pull request carries its own build instead of
pushing the rebuild after merge. Update contributors opens or refreshes one
pull request on bot/contributors. The wall is full, so wall-sync and its
script are removed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WvtxFy8iMNYHYoobbZsvD6
The Build blog workflow could not push the regenerated docs/blog to the
protected main branch (GH006), so HarnessMD#487 and HarnessMD#488 merged without their
built pages. This commits that output.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
The dry run of the blog SEO mission. Four intents were claimed; three
passed the hard checks in gate.mjs and a separate fact checking review:

- how-to-add-an-mcp-server-to-claude-code (task guide)
- codex-cli-vs-claude-code (comparison)
- how-much-does-claude-code-cost (question)

Each links up to a pillar and across to two posts, and one older post
now links to each (mcp-and-skills-in-a-hive, best-ai-coding-agents,
the-multi-agent-cost-playbook). Heroes and notes are drawn in code.
The fourth intent, best local LLM for coding, is held for a freshness
review. docs/blog is left to the Build blog workflow.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
Every blog PR now ships its own docs/blog and docs/sitemap.xml, because
main is protected and the Build blog workflow cannot push to it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
…-to-main

ci: stop pushing to protected main, remove wall-sync
What Is an MCP Server? (k046) and How to Use Claude Code Plan Mode (k030),
each through the gate and two fresh fact reviews. Code drawn heroes and
notes, backlinks from how-to-add-an-mcp-server-to-claude-code and
agent-security-and-sandboxing, and the built docs/blog and sitemap.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
The rendered description broke "--permission-mode" across a line, which
read like a dash. Rebuilt docs/blog.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
New posts: grok-bot-alternatives, claude-code-max-plan-tips,
codex-max-plan-tips, herdr-alternatives, omniagent-alternatives.
Backlinks from how-much-does-claude-code-cost, codex-cli-vs-claude-code,
tmux-and-scripts-vs-an-agent-harness, crewai-autogen-vs-a-local-agent-harness
and why-local-first-matters-for-ai-agents. Built docs/blog and sitemap.
OmniAgent images follow in the next commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
Founder feedback on HarnessMD#514: draw the OmniAgent images with the code
pipeline instead of waiting on the image quota, and move each Munder
Difflin mention up (second in alternatives lists, near the top of the
two plan guides) with a clearer free and open source pitch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
Founder request on HarnessMD#514: every Munder Difflin plug links to
https://harnessmd.com/download.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
chaitanyagiri and others added 26 commits September 14, 2026 21:57
blog: First Hour rewritten for 0.5.2 Pro with real screenshots, new Slack connect guide
docs: munderdiffl.in gets its own download page, themed like the site
how-to-install-gemini-cli, aider-vs-claude-code, is-ollama-good-for-coding, with code drawn heroes and notes, backlinks from best-ai-coding-agents, how-to-install-codex-cli and how-to-connect-ollama-to-claude-code, and the rebuilt blog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
…Munder Difflin

New developer guide built on the demo office screenshots from the First Hour shoot: morning brief, pull request sweep, memory, voice and Slack, and the limits to set. Backlink from your-first-hour-with-munder-difflin. Rebuilt blog.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
…build the blog

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
Google Ads account 860-497-8496 has a conversion action "Outbound click",
marked primary, but no tag existed on the site, so nothing could be measured
and no remarketing list could start filling.

Adds the Google tag AW-18388216863 to the head of docs/index.html,
docs/download.html and the blog layout, and fires the conversion from the
same a[download] links PostHog already watches on the download page.

Two deliberate choices:
  * The tag only loads when Do Not Track is off, matching the rule the
    PostHog block on this site already follows.
  * The conversion listener is separate from the PostHog listener, so
    neither tracker depends on the other still being there.

Enhanced conversions was left off in the account. It needs an email or phone
at the point of conversion and the download click collects neither, so it
would have nothing to send.

The blog is rebuilt because the layout changed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
…hout a PR

The role could only be granted by merging a pull request whose body carried
a "Discord: handle" line. Four people on discussion HarnessMD#533 gave their handle in
a comment instead, one of them in a reply to another comment, and there was
no way to grant it to them short of doing it in the Discord UI.

Adds a workflow_dispatch trigger taking a list of handles, separated by
spaces or commas. The merge path is unchanged.

The input is handled with the same discipline as the PR body: it arrives in
an env var, is never interpolated into the shell, and every handle must match
^[A-Za-z0-9._]+$ before it reaches a command. Anything else is dropped. A
handle that is not in the server is still a skip, not a failure.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkBAGTNhQsCrhyBFcnG9AS
…rdiffl.in/wall-data.json

The Founding Supporter wall file paired every name on it with the real Razorpay
payment id of that person's transaction, and it has been served publicly at
https://munderdiffl.in/wall-data.json for weeks. Verified live today: HTTP 200,
103 rows, a payment id on every one of them, byte identical to main.

The dispatch said 95. It is 103, and all 103 are genuine ids matching
pay_<14 alphanumeric>, all distinct, dated 2026-08-14 to 2026-09-09.

WHAT CHANGED. The payment_id field is gone from all 103 rows. Nothing else.
Every name and every date is kept exactly as it was, because the wall is a wall
of honour and those people put their names on it on purpose. The file keeps its
existing one object per line shape so the diff reads as a field removal rather
than a reformat.

WHY NOTHING ELSE HAD TO GO. The file only ever had three fields: name, date,
payment_id. No emails, no order ids, no refund ids, no amounts, nothing internal.
I checked the whole file, not a sample.

WHY THE PAGE DOES NOT NEED A FIX. docs/wall.html reads exactly three properties
off an entry: name, link and date. It never reads payment_id. link is optional
and no row has ever carried one. So the wall renders unchanged. Nothing else in
this repository reads wall-data.json, and no test asserts its shape.

KNOWN CONSEQUENCE, OUTSIDE THIS REPOSITORY. The local metrics dashboard fetches
this exact URL and joins on the field being removed, at
/Users/chaitanya/Documents/MDv0.3.0/dashboard/collectors/razorpay.mjs:163. It
will not crash: wall_published stays correct because it is just a row count, but
wall_pending will silently report every eligible captured payment instead of the
true figure. That file is not in this repository and is not mine to change. It
needs a one line fix, and the metric may simply be finished now that the wall is
full and closed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PogxmT9ULRQSYbfs1oigLx
The Teams tier no longer sells itself. The per seat month price, the per seat year price, the size slider with its running total, the trial chip and the card at checkout sentence are all gone, and nothing replaced them with a smaller number or a range. The tier says instead that Teams is arranged with us on a call. The FAQ says the same: the answer about being charged during a trial is now an answer about how you get Teams at all, and the cost answer prices Teams with the team on the call. The free and Pro figures are untouched, and so is the Pro styling, the Pro copy and the release version.

All four Teams calls to action now point at the same place, https://cal.com/chaitanya-giri-dk45ov/30min: the hero link that used to read Munder Difflin for Teams, the Teams feature card, the pricing tier button and the closing button. The feature card used to carry a second, different calendar link, which is now gone, so exactly one booking destination exists on the site.

The calendar is the destination on purpose and for now. An intent form at /teams/talk would also catch someone who reads the page and does not book, but it is not built yet and it needs the founder's own answers first. Pointing a live public page at a route that does not exist would be a dead end, so the four links go to the calendar today and move to the form in one edit when it ships. The comment above the pricing section says so.

The download line said paid plans start with a 14 day trial. Only Pro does now, so it names Pro.

The seat slider script and the CSS for the slider and its total went with the markup it drove. What a company evaluating Teams still needs is kept: what Teams does, the sealed per device answer, the admin console, and that each person runs under their own keys.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PogxmT9ULRQSYbfs1oigLx
The only mention of refunds on munderdiffl.in/terms.html was one clause
inside Donations. We have been selling Pro licences for weeks with no
published refund position on that page.

Adds section 09, Refunds and cancellation: payments are final, Pro is a
one time term so there is nothing to cancel and nothing renews, a
recurring plan stops from the account without refunding past charges, and
one discretion line so a goodwill refund does not contradict the terms.
Keeps the legal carve out so the clause stays enforceable.

Donations now points at the new section instead of carrying the policy on
its own, Paid services gains a short paragraph on Pro so the page matches
what we actually sell, and the sections after it are renumbered.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkBAGTNhQsCrhyBFcnG9AS
Someone who reads only the summary at the top should know payments are
final before they pay, not after. One sentence, carrying the good news
first: Pro is a one time term, nothing renews, nothing to cancel.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UkBAGTNhQsCrhyBFcnG9AS
app.harnessmd.com/releases/ is an open directory index of every build back to
0.4.10 and it is being turned off (founder, 17 Sep 2026: nobody sees a release
older than v0.5.2). Three links here point straight at it and would 404 the
moment that happens, so this ships with the server change rather than after it.

The sentence is not restored as it was. "Every release" promised a list of older
builds, which is the promise being withdrawn, and "with notes and checksums"
promised something the new destination does not carry. It names what is actually
there: the notes for the version on the button, at harnessmd.com/download.

Checksums are unaffected. SHA256SUMS-v<version>.txt still serves by exact
filename, as does every installer, including the three direct links on this page.

The blog post is edited in BOTH the markdown source and the built page, so the
next blog build does not put the dead link back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PogxmT9ULRQSYbfs1oigLx
The blog gate rebuilds and fails on any difference. Running it left exactly one
line: the root lastmod, 16 Sep to 17 Sep, which the postbuild step stamps.

Worth recording because it is the useful half: docs/blog came back CLEAN. The
built post I hand edited matches byte for byte what the builder produces from
the markdown, so the source and the page do not disagree.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PogxmT9ULRQSYbfs1oigLx
…nload

docs/download.html was a second, hand maintained copy of the download page:
version, published date and all three file sizes were typed into the HTML.
harnessmd.com/download reads the same facts off disk. Both say 0.5.2 today and
would disagree the day 0.5.3 ships, so this leaves one page.

Measured before changing anything, 17 Sep 2026. The URL gives up nothing:
0 clicks and 16 impressions in three months (Search Console, 3 month window),
from three queries, all of them our own brand name, on which the homepage
already ranks. No inbound links and no ranking keywords (OpenSEO, exact URL
scope). It was never in sitemap.xml, and no blog post links to it.

GitHub Pages cannot serve a 301, so the stub redirects three ways: a meta
refresh, which crawlers treat as permanent and which survives JavaScript being
off; a cross domain canonical for anything that ignores the refresh; and
location.replace, so the back button does not bounce the visitor forward again.
A visible link is the fallback for anyone none of those reaches.

The five homepage buttons now link straight to harnessmd.com/download rather
than taking the extra hop.

Carries over the Google Ads conversion. download.html was the only page on this
site with a[download] links, so it was the only one that could fire the
"Outbound click" action. The homepage now fires it on the click out to the
download page instead. That counts one step earlier in the funnel, reaching the
download page rather than picking an installer; the accurate fix is the same
tag on harnessmd.com/download, which lives in the server repo.

Version on this repo stays 0.4.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
…stination

Kevin is putting the Google tag and the conversion listener on
harnessmd.com/download, at the click on an actual installer. Keeping the carry
here would report the same conversion action, AW-18388216863/qnM3CI670_kcEJ_Yl8BE,
a second time on the way out, for one visit.

It was also covering almost nothing: 22 pages on this site link to
harnessmd.com/download and this listener saw one of them, the homepage. The tag
on the destination sees all 22, plus arrivals through the retired URL and any
inbound link from elsewhere.

The redirect and the five repointed homepage buttons are unchanged. Version
stays 0.4.6.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DKhjmRPTpdrv1ewjdnhar3
Gate the boot-time /remote-control submit behind REMOTE_CONTROL_ON_STARTUP
(false). Aaron enables remote control manually when he wants phone
approvals; flip the flag to restore the old behavior.
Upstream's 65 commits since this branch last integrated touch no application
code at all: the delta is 428 generated documentation files, 169 blog files,
four workflow files and one file each under tools, scripts and .claude.
`git diff 3e4f9f6 upstream/main -- src/ test/` is empty, and the version
field is 0.4.6 on both sides.

Integrated as a merge rather than a flat replay. This branch has always taken
upstream by merging (seven prior merge commits), so replaying its 195 commits
re-opens conflicts those merges already settled: three surfaced in the first
nine commits, one of them against a hardcoded model array upstream has since
deleted in favour of a JSON catalog, whose intent this branch already carries.

Nothing on this side changes. All 285 files this branch has modified since the
merge base survive the merge byte-identical, and the suite is unchanged across
it: 1427 of 1488 passing, with the same 59 pre-existing failures and the same
one cancelled test before and after.

Claude-Session: https://claude.ai/code/session_01JANvLdyJ2Lav9KNdxRNvjY
@github-actions

Copy link
Copy Markdown

🚫 This PR is missing its before/after evidence

Every pull request here has to show its work. Screenshots or a short screen recording, before the change and after it.

  • Before — no image or video under that heading
  • After — no image or video under that heading

How to fix it: edit the description, keep the ### Before and ### After headings from the template, and drag an image or video under each. GitHub uploads it inline. This check re-runs the moment you save.

A bug fix with no visible surface still needs it: show the failing behaviour, then the same steps passing. A terminal recording is fine.

Genuinely nothing to show — a CI tweak, a typo, a dependency bump? A maintainer can apply the no-visual-change label. Please don't ask unless it truly has no observable effect.

📖 CONTRIBUTING.md → Evidence is mandatory

@aaroncoville
aaroncoville changed the base branch from main to theme/sixth-history September 25, 2026 05:11
@aaroncoville
aaroncoville merged commit 615b31c into theme/sixth-history Sep 25, 2026
0 of 2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants