The Skill Pack Pages That Linked to Nothing

The Where This Sits block rendered on a skill pack page, showing five rungs with You Are Here on the pack rung

Two of our published skill-pack pages linked to nothing at all. Not a broken link — zero links. They had been that way for weeks, on sites we point workshop attendees at, inside daily reports that all said green.

13published pages audited across 6 domains
2 → 0dead ends, after
16shipped references pointing at a double 301

Dennis asked a question that sounded like a content question and was actually an architecture question: the Task Library shows 239 skills, the packs show up on six domains, agents run those skills — does a visitor landing on any one of those pages understand how it fits together? And does it say anywhere that owning skills is not the same as getting work done?

So we audited the link graph instead of guessing. Pull every one of the 13 agent/skill pages over authenticated REST, decode any base64 payload, extract every link that points at one of the other twelve, print the adjacency both directions. Ten minutes of work, and the answer was not close.

Audit the graph before you trust it

NodeWhat the audit found
aibuilderspotlight.com/skill-packDead end. Zero outbound links to anything in the system.
dunkerspotlight.com/set-up-claudeDead end. Zero outbound links.
sigrun.com/somba-agentsOne outbound link. A partner’s members’ area with no route back into the system it belongs to.
blitzmetrics.com/task-library-dashboardThe 239-skill page linked neither the packs that contain those skills nor the agents that run them.
localservicespotlight.com/business-authority-packLinked only its sibling pack. No path up to the directory or the hub.
dennisyu.com/wichitaNo link to the trunk.
localservicespotlight.com/ai-agent-application-passwordA double 301 — and 16 of our own files, including four published skill packs, still told installers to go there.
Nothing was broken. Every page returned 200. Every pack carried the right date. Every zip byte-matched its local build. The daily job checked everything it knew about, and every single check passed — because publishing a page and connecting a page are two different jobs, and only the first one had an owner.

Name the rung that was missing

The audit explained the holes. It did not explain why the holes were invisible, and that turned out to be the same gap Dennis had named: the argument tying the whole thing together was written down nowhere.

A skill is a document. A pack is a folder of documents. Neither one does any work. Work happens when a job runs those skills on a schedule, checks its own output, and keeps its files somewhere it can read them again tomorrow. Miss any of the three and the pack sits on the site looking current while it goes a month out of date. We had a page for every rung except that one.

So the structure became a five-rung ladder — Skill, Pack, Agent, Job, Proof — and the missing rung got its own definitive article at blitzmetrics.com/persistent-agents.

Five rungs: skill, pack, agent, job, proof, with the job rung highlighted and split into a schedule, a QA cycle and working files
The rung nobody ships. You can own the first three and still have nothing running.

Render the same block on every node

Twelve bespoke “related links” sections would have been twelve chances to drift. One block, defined once, rendered on all of them, with the current rung marked.

The Where This Sits block as it renders on every node, showing the five rungs with You Are Here on the pack rung
Land on any of the twelve and you see the whole tree and your position in it. This is the live markup, generated from one Python module.

Three design calls worth stealing:

DecisionWhy
One definition, in codeSystem-Hub/system_tree.py holds every node, its rung, its sibling, and the block. Generators import it. A tree that lives in twelve page bodies is twelve things to keep in sync by hand.
Siblings in a closed ringEach pack page links exactly one other pack page, arranged so the seven form a loop. A crawler can walk all of them; no two pages point at each other, which reads as link exchange; and the pages do not all look identical, which a full mesh guarantees.
Counts derived, never typed“There are 239 of them” is read from the Task Library manifest at render time. A typed count is a date badge with extra steps.

Fix at the generator, not on the page

Two of the twelve pages — the Skill Pack Library and the Asset Tracker — are rebuilt from scratch by their own Python generators on a schedule. Editing those live would have looked like a clean success: HTTP 200, block present in the rendered DOM, verification green. The next scheduled rebuild would have erased it silently, and the job that erased it would still have reported success.

So the work split by owner: generated pages got the block added to their generator, plain pages went through REST, and the three base64-payload pages were decoded, edited, and re-encoded. One writer per file. The trunk page was the awkward one — it had picked up three hand-added blocks since its last build, so regenerating it from the local template would have deleted all three. That one got surgical marker-guarded edits through a sub_once() that raises when its anchor is missing, rather than a restore.

Gated pages are verified differently. sigrun.com/somba-agents is member-password-protected, so an anonymous fetch returns the password form. A naive “is the link on the page” check would fail on a perfect publish — and pass on a broken one. It is verified by authenticated read-back of the decoded payload instead.

Collapse the redirect you were shipping

The dead URL is the part worth reading twice. localservicespotlight.com/ai-agent-application-password/ had become a double 301 — one hop to a renamed article, a second to its current home. It still resolved, so nothing complained. It was sitting in boil-the-ocean.md and video-repurposing-agent.md across four public packs, in two generators, in the daily checklist, in the project’s own CLAUDE.md, and on the trunk page of the entire system.

A redirect chain is not a broken link, which is exactly why it survives. Every check passes, every page loads, and the crawler discounts the destination. Sixteen references were repointed at the source, then the daily propagation job pushed the corrected packs to all ten live surfaces the same night — so the fix reached everyone who downloads a pack tomorrow, not just the pages we happened to be editing.

Write the check the same day

The structure is not the deliverable. The thing that asserts the structure still exists tomorrow morning is the deliverable.

$ python3 System-Hub/verify_link_graph.py OK the-system OK skill-packs OK dealcon OK task-library OK asset-tracker OK wichita OK build-agents OK business-pack OK aibuilder-pack OK persistent-agents OK entrepreneur-pack OK dunker-pack OK somba-agents graph nodes reachable : 13/13 orphans : none dead ends : none short URL : /persistent -> https://blitzmetrics.com/persistent-agents/ OK Link graph intact: every node carries the ladder, no orphans, no dead ends, no redirect chains.

It is wired into the generated daily checklist next to the two verifiers added last week, and it exits non-zero on any orphan, dead end, missing rung, reintroduced dead URL, or redirect hop. On its first run it also caught two things this write-up would otherwise have claimed were already fixed: the trunk page still carried the dead app-password link inside a hand-added block, and the loop copy still said “honest about the token cost,” which breaks a standing house rule.

One deliberate softening. The first version failed six pages on that same house-word rule. A fleet sweep last week found roughly 84 hits across twelve verticals, most of them either one generator emitting identical copy twelve times or Dennis’s own quoted speech, where the word is the point. Failing the daily job on those makes it permanently red, and a permanently red check gets ignored exactly like a permanently green one. The rule is now enforced hard on the block we generate and reported as a note for the rest of the page.

What it cost

LineCountDetail
Live pages written1413 tree nodes across 6 domains, plus the companion article
New code1,114 linessystem_tree, apply_system_tree, verify_link_graph, publish_persistent_agents, wire_trunk
Generators patched3build_skillpacks_index, build_asset_tracker, propagate_all_packs
One-off scripts deleted1the throwaway audit, promoted into the permanent verifier
Skill files updated604 learning notes harvested into every pack’s source
Packs republished13 → 10 surfaces8 live zips byte-matched to the local build
Modelclaude-opus-5one session, roughly three hours wall clock, unattended writes to six domains
Human equivalent2–3 daysthe audit alone is a day of clicking; the 60-file harvest is not something a person does by hand

Token count was not instrumented on this run, so there is no figure to publish. That is itself the lesson of the article — the number you did not arrange to capture is a number you do not have.

What is still open

ItemState
Task Library learning coverageThe harvest reports 1 lesson across 241 skill files in the Task Library, against 80–112 in each sibling pack. The learning notes are written against agent-skill slugs that mostly do not exist there, so it is structural rather than rot — but it is the same shape as the failure that starved a pack for a month, and it wants a decision on how field lessons map onto 239 task SOPs.
RankMath REST on blitzmetrics.comEvery POST to /wp-json/rankmath/v1/* returns 403 from the host’s WAF while wp/v2 POSTs succeed. Worked around by driving the SEO title and description through the post title and excerpt, which RankMath falls back to. Reported to the web team.
The legacy double 301Our own references are repointed. The old URL still costs two hops for anyone holding an older copy of a pack; collapsing it needs a redirect-table edit in wp-admin.

THE DELIVERABLE

The rung that was missing, written up as a definitive article — and the ladder it sits on, now live on all thirteen pages.

Read Persistent Agents See The System Install a skill pack
Dennis Yu
Dennis Yu
Dennis Yu is the CEO of Local Service Spotlight, a platform that amplifies the reputations of contractors and local service businesses using the Content Factory process. He is a former search engine engineer who has spent a billion dollars on Google and Facebook ads for Nike, Quiznos, Ashley Furniture, Red Bull, State Farm, and other brands. Dennis has achieved 25% of his goal of creating a million digital marketing jobs by partnering with universities, professional organizations, and agencies. Through Local Service Spotlight, he teaches the Dollar a Day strategy and Content Factory training to help local service businesses enhance their existing local reputation and make the phone ring. Dennis coaches young adult agency owners serving plumbers, AC technicians, landscapers, roofers, electricians, and believes there should be a standard in measuring local marketing efforts, much like doctors and plumbers must be certified.