📝 SEO & Content 6
Improving a Belgian energy page
Operational
▸/improve-be-energy {url}
The Belgian energy front end of the /improve engine, in French and in Dutch: the energie/ and mazout/ trees of selectra.be and callmepower.be (fr/** and nl/**), and the whole of mon-energie-verte.be and mijn-groene-energie.be, which carry no language prefix.
It replaced /improve-be-fr and /improve-be-nl on 2026-09-24: Belgian skills are now split by category, and a telecom skill will follow. The language is not chosen by the operator. The engine resolves each page to belgium-fr or belgium-nl, and the skill loads that language's rules: French typography requires a non-breaking space before : ; ? ! that Dutch forbids.
The skill delegates the whole pipeline to the shared engine. What it adds are the Belgian questions asked before any edit (partner status by three signals rather than a hand-maintained registry, region since there is no national Belgian price, whether a supplier still sells) and the language layer (typography, Belgian authorities only, a SERP read in the page's locale, internal links that never cross the FR/NL boundary).
Energy · mon-energie-verte.be
Energy · mijn-groene-energie.be
Energy · selectra.be
Energy · callmepower.be
/improve-be-energy {url}The Belgian energy front end of the /improve engine, in French and in Dutch: the energie/ and mazout/ trees of selectra.be and callmepower.be (fr/** and nl/**), and the whole of mon-energie-verte.be and mijn-groene-energie.be, which carry no language prefix.
It replaced /improve-be-fr and /improve-be-nl on 2026-09-24: Belgian skills are now split by category, and a telecom skill will follow. The language is not chosen by the operator. The engine resolves each page to belgium-fr or belgium-nl, and the skill loads that language's rules: French typography requires a non-breaking space before : ; ? ! that Dutch forbids.
The skill delegates the whole pipeline to the shared engine. What it adds are the Belgian questions asked before any edit (partner status by three signals rather than a hand-maintained registry, region since there is no national Belgian price, whether a supplier still sells) and the language layer (typography, Belgian authorities only, a SERP read in the page's locale, internal links that never cross the FR/NL boundary).
python .claude/skills/improve-be-energy/scripts/be_scope.py {page}be_scope.py asks the engine which market the page resolves to, then checks it sits under the site's energy paths. A telecom or other-vertical page is refused with a pointer to what applies instead.
python .claude/skills/improve-be-energy/scripts/be_gate.py {page}be_gate.py picks the French or Dutch rules from the page's resolved market and reports in that language. It measures and decides nothing. Mechanical findings block: spacing, currency form, em dash, formal address, a text leak from the other language. Editorial ones are reported for the human.
python .claude/skills/improve-be-energy/scripts/be_provider_check.py --site {site} --provider {provider}be_provider_check.py measures partner status, region and freshness, and decides nothing.
The engine could not see <x-be.faq>, <x-be.universal-faq>, <x-be.faq-accordion> or <x-faq-schema>, all four of which do emit a valid FAQPage: 20 points lost under a hard floor of 60, across 379 Dutch-language pages.
A Dutch-language tariff cluster whose prices lived only in client-side JavaScript lost 108 of its 144 clicks.
Belgian telecom editorial house rules
Operational
▸/be-telecom-house-rules {url}
Audits and fixes the permanent editorial house rules on a Belgian telecom article, on callmepower.be AND selectra.be, in French (/fr/telecom) as well as in Dutch (/nl/telecom): bold words in the hero, a paragraph of at least two lines after every heading, FR/NL punctuation spacing and non-breaking spaces, author byline and schema, "abonnement" never "forfait", contextual internal links, Blade integrity and an HTTP 200 smoke test.
Auto-fixes the mechanical, flags the editorial calls. Symbol and icon alignment is NOT re-patched page by page: it is owned by a central CSS rule in each site's css/app.css, and the skill only verifies the markup pattern.
Telecom · callmepower.be
Telecom · selectra.be
/be-telecom-house-rules {url}Audits and fixes the permanent editorial house rules on a Belgian telecom article, on callmepower.be AND selectra.be, in French (/fr/telecom) as well as in Dutch (/nl/telecom): bold words in the hero, a paragraph of at least two lines after every heading, FR/NL punctuation spacing and non-breaking spaces, author byline and schema, "abonnement" never "forfait", contextual internal links, Blade integrity and an HTTP 200 smoke test.
Auto-fixes the mechanical, flags the editorial calls. Symbol and icon alignment is NOT re-patched page by page: it is owned by a central CSS rule in each site's css/app.css, and the skill only verifies the markup pattern.
Daily spot electricity price article
Operational
▸/be-stroomprijs-dagelijks
Generates the daily editorial article on the day-ahead electricity price for selectra.be, in Dutch: fetches the day's raw EPEX SPOT BE data, picks an editorial angle, and writes a unique date-stamped STATIC Blade page.
The data is frozen into the file at generation time, so the dated archive never needs a historical endpoint. The Dutch-language twin of /prix-dynamique-daily, adapted to Belgium and to the wholesale feed.
Energy · selectra.be
/be-stroomprijs-dagelijksGenerates the daily editorial article on the day-ahead electricity price for selectra.be, in Dutch: fetches the day's raw EPEX SPOT BE data, picks an editorial angle, and writes a unique date-stamped STATIC Blade page.
The data is frozen into the file at generation time, so the dated archive never needs a historical endpoint. The Dutch-language twin of /prix-dynamique-daily, adapted to Belgium and to the wholesale feed.
Day-28 follow-up on an improved page
Being documented
▸/follow-up-improve-be [{url}]
Did the rework work? 28 days after a page goes through /improve, /improve-be-energy or /crea-article-be, the follow-up compares the 28 days before and after and answers with one word: Yes, Partly, Not yet, No, Too early to tell. /follow-up-improve-be is the Belgian front end of the shared /follow-up-improve: the measurement and the scoring rule are the shared ones, run on the four Belgian sites in French and Dutch, every vertical included: energy, telecom, insurance, banking.
Only a page that went through an improve skill has a follow-up: the improve skill books it. Hand edits, house-rules passes and fleet-wide changes book none.
On 8 October 2026 the four registries hold 107 follow-ups: selectra.be 18 (13 taken out of the queue after the 21 August demotion, 5 waiting), callmepower.be 82, mijn-groene-energie.be 6, mon-energie-verte.be 1. The first one falls due on 10 October.
Energy · selectra.be
Telecom · selectra.be
Energy · callmepower.be
Telecom · callmepower.be
Energy · mijn-groene-energie.be
Energy · mon-energie-verte.be
/follow-up-improve-be [{url}]Did the rework work? 28 days after a page goes through /improve, /improve-be-energy or /crea-article-be, the follow-up compares the 28 days before and after and answers with one word: Yes, Partly, Not yet, No, Too early to tell. /follow-up-improve-be is the Belgian front end of the shared /follow-up-improve: the measurement and the scoring rule are the shared ones, run on the four Belgian sites in French and Dutch, every vertical included: energy, telecom, insurance, banking.
Only a page that went through an improve skill has a follow-up: the improve skill books it. Hand edits, house-rules passes and fleet-wide changes book none.
On 8 October 2026 the four registries hold 107 follow-ups: selectra.be 18 (13 taken out of the queue after the 21 August demotion, 5 waiting), callmepower.be 82, mijn-groene-energie.be 6, mon-energie-verte.be 1. The first one falls due on 10 October.
Partner clicks, internal linking and AI reads need Metabase access and a Cloudflare token with analytics on the site's zone, on the machine that runs the measurement. Without them the results page shows Google clicks and says which figure is missing and why: a missing figure counts neither for nor against. Not yet run end to end on a due Belgian page.
/follow-up-improve-beEvery follow-up of the four sites, French and Dutch counted apart: due, report ready, waiting, treated. Free: nothing is measured or changed, a human picks the page. Entries a human took out of the queue are shown apart with their reason and never measured — the shared list still shows the 13 selectra.be telecom pages voided after 21 August as due.
python .claude/skills/follow-up-improve-be/scripts/be_followups.py --twin {url} --liveThe twin comes from the site's hreflang map and is checked against the public page. When both are due, one run handles both, each under the rules of its own language (typography is inverted between French and Dutch). A twin without a follow-up is never edited silently: it is named as "to reread" when a shared fact changes.
/follow-up-improve-be {url}The shared /follow-up-improve does the work: same duration before and after, compared with the rest of the section, exact keywords won and lost, the page reread as it renders, fixes applied with judgment. On selectra.be, a window crossing the 21 August demotion is re-read on two windows on the same side of that date.
Each page gets the rules of its vertical before closing: energy follows /improve-be-energy, telecom /be-telecom-house-rules. Insurance and banking have no Belgian skill: their rules are the selectra.be convention's (partner registry, mandatory non-partner content, monetisation box), checked by hand. Two gaps are reported rather than filled: Dutch banking pages and callmepower.be insurance have no written rules yet.
python .claude/skills/follow-up-improve-be/scripts/be_followups.py --index --measureThe team scoring rule (1 partner click = 1 point, 2 internal-link clicks = 1, 20 Google clicks = 1, 10 AI reads = 1; score = gain × growth), ranked among Belgian follow-ups only: the shared hub and its ranking keep French sites only. One page gathers them all: latest follow-ups as cards, a table per site by section then page, every follow-up sorted by points with site, language and type filters.
Finding the articles that do not exist yet
Operational
▸/content-gap {site}/{language}
The inverse question of /improve: /improve reworks a page that exists, /content-gap asks what the site captures NOWHERE. It never writes a page and never commits.
It runs per LANGUAGE, never per domain — French and Dutch Belgium are two markets with different regulators and opposite typography, so each keeps its own registry and its own competitors. The four perimeters were onboarded on 23 September 2026 and hold 18 candidate cards: 14 on selectra.be/fr, 3 on selectra.be/nl, 1 on callmepower.be/fr, and none on callmepower.be/nl — "no viable gap" being a result, not a failed run.
Energy · selectra.be
Telecom · selectra.be
Insurance · selectra.be
Energy · callmepower.be
Telecom · callmepower.be
/content-gap {site}/{language}The inverse question of /improve: /improve reworks a page that exists, /content-gap asks what the site captures NOWHERE. It never writes a page and never commits.
It runs per LANGUAGE, never per domain — French and Dutch Belgium are two markets with different regulators and opposite typography, so each keeps its own registry and its own competitors. The four perimeters were onboarded on 23 September 2026 and hold 18 candidate cards: 14 on selectra.be/fr, 3 on selectra.be/nl, 1 on callmepower.be/fr, and none on callmepower.be/nl — "no viable gap" being a result, not a failed run.
The competitor axis needs an Ahrefs CSV exported by hand, about ten minutes. Only selectra.be/fr had one on 23/09/2026: elsewhere the figures are Search Console impressions over twelve months, not monthly search volumes.
The language perimeter is the unit of work: it decides the pages inventoried, the Search Console pull, the registry written and the competitors measured. One config file per perimeter; copying one onto another is forbidden, most of its values being false elsewhere.
python .claude/skills/content-gap/scripts/coverage_map.py --site {site}/{language}A local inventory of the perimeter's pages, H2 texts included, crossed with twelve months of Search Console queries. It surfaces demand we are shown for but capture weakly, or capture on an off-topic page. Free, and it delivers most of the ideas on its own.
python .claude/skills/content-gap/scripts/competitor_gap.py --site {site}/{language}Needs a Content Gap CSV exported by hand from Ahrefs, scoped to the language subtree in Path mode, country BE. When the export is missing the step STOPS and prints the protocol: it never approximates competitor data from memory. Covered on selectra.be/fr only.
Each idea is tested against our own pages, H2 level included, and against the redirections. A retired URL is a business decision, not a gap; but one landing on a LIVE page of the same subject is a regrouping. Two Belgian segments were wrongly blocked on that confusion.
python .claude/skills/content-gap/scripts/gap_registry.py list --site {site}/{language} --status proposedEvery kept idea becomes a card: proposed, then accepted or rejected by a human, then created once the article ships. A rejection requires a written reason — that is what stops the idea resurfacing unexplained at the next run. A figure with no source is refused.
Porting a chart from the legacy Drupal site
Operational
▸/chart-from-drupal
Ports an evolution chart — a Chart.js time series — from the legacy selectra.be Drupal site onto a Blade page of this CMS. Reuses the existing shared <x-line-chart> component: no external JavaScript, no CDN. selectra.be only.
Energy · selectra.be
/chart-from-drupalPorts an evolution chart — a Chart.js time series — from the legacy selectra.be Drupal site onto a Blade page of this CMS. Reuses the existing shared <x-line-chart> component: no external JavaScript, no CDN. selectra.be only.
🗄️ APIs, Data & Knowledge 3
Belgian knowledge corpus
Being documented
The verified Belgian facts, filed per department and maintained by hand by humans, never by a skill. Every ficha carries its last-verified date and its primary sources.
The real state today: belgium-energy holds 26, and it is the only mature corpus. belgium-telecom holds 3. belgium-insurance, belgium-finance and belgium-moving hold nothing but an empty index. belgium-water does not even have a knowledge folder.
Energy · belgium-energy
Telecom · belgium-telecom
Insurance · belgium-insurance
Banking · belgium-finance
Moving · belgium-moving
Water · belgium-water
The verified Belgian facts, filed per department and maintained by hand by humans, never by a skill. Every ficha carries its last-verified date and its primary sources.
The real state today: belgium-energy holds 26, and it is the only mature corpus. belgium-telecom holds 3. belgium-insurance, belgium-finance and belgium-moving hold nothing but an empty index. belgium-water does not even have a knowledge folder.
The imbalance is the standout finding of this map: energy is documented, the five other Belgian departments are not. That is the first prioritisation call to make.
Market liberalisation and regulation, social tariffs and protected customers, grants and subsidies, smart meters, solar panels and prosumers, wholesale markets and price formation, energy poverty, building energy performance certificates, energy communities, electric vehicles.
The corpus seeded by /knowledge-be-telecom: outages and compensation, plus the index and the _DRIFT.json drift file, which tracks which pages diverge from the canonical fact.
An _INDEX.md, and no ficha. All the knowledge still lives inside the pages themselves, which means nowhere verifiable.
The department holds a config folder and nothing else. No knowledge, no provider, no views.
Building the Belgian telecom knowledge corpus
Being documented
▸/knowledge-be-telecom
Builds and refreshes the belgium-telecom corpus, the Belgian twin of the 37 france-telecom fichas. It harvests the facts asserted across the 1,400+ telecom pages of selectra.be and callmepower.be, in French and in Dutch, VERIFIES each one against a primary source — IBPT/BIPT, SPF Économie, the Moniteur belge, or an operator's own official page, never a hand-built URL — then writes the ficha with its verification date and its sources.
Every ficha declares machine-runnable probes, so a script reports reproducibly which pages assert the canonical value, which diverge, and which need a human call. Producer only: it never edits a page and never commits.
Telecom · belgium-telecom
/knowledge-be-telecomBuilds and refreshes the belgium-telecom corpus, the Belgian twin of the 37 france-telecom fichas. It harvests the facts asserted across the 1,400+ telecom pages of selectra.be and callmepower.be, in French and in Dutch, VERIFIES each one against a primary source — IBPT/BIPT, SPF Économie, the Moniteur belge, or an operator's own official page, never a hand-built URL — then writes the ficha with its verification date and its sources.
Every ficha declares machine-runnable probes, so a script reports reproducibly which pages assert the canonical value, which diverge, and which need a human call. Producer only: it never edits a page and never commits.
python scripts/scan_facts.pyThe result is written to knowledge/_DRIFT.json, versioned, because the failure this closes is a fact known only to session memory.
Per-site data registries
Operational
Every Belgian site carries its own reference tables as flat PHP, versioned in Git: providers and their Dutch names, partner and non-partner CTAs, the health index, the 2025 municipality mergers, stores, propane prices, redirects, FR-to-NL mapping tables.
These files are maintained by hand and do get things wrong: a site registry never proves on its own that a provider is a partner.
Energy · callmepower.be
Energy · selectra.be
Energy · mijn-groene-energie.be
Energy · mon-energie-verte.be
Every Belgian site carries its own reference tables as flat PHP, versioned in Git: providers and their Dutch names, partner and non-partner CTAs, the health index, the 2025 municipality mergers, stores, propane prices, redirects, FR-to-NL mapping tables.
These files are maintained by hand and do get things wrong: a site registry never proves on its own that a provider is a partner.
Documented trap: four non-partners were promoted to partners on live pages on 8 September 2026, by trusting the site registry alone.
💶 Monetisation & Conversion 1
Monetisation: partner and non-partner CTAs
Being documented
The conversion system of the Belgian sites rests on CTA tables split by status: partner-cta.php and non-partner-cta.php on mijn-groene-energie.be and mon-energie-verte.be, a dedicated monetisation.php on mon-energie-verte.be, phone and energy tokens as JSON on callmepower.be.
Call routing goes through single-segment /fr/selection/{key} pages, never through a direct tel: link.
Energy · mon-energie-verte.be
Energy · mijn-groene-energie.be
Energy · callmepower.be
Insurance · selectra.be
The conversion system of the Belgian sites rests on CTA tables split by status: partner-cta.php and non-partner-cta.php on mijn-groene-energie.be and mon-energie-verte.be, a dedicated monetisation.php on mon-energie-verte.be, phone and energy tokens as JSON on callmepower.be.
Call routing goes through single-segment /fr/selection/{key} pages, never through a direct tel: link.
For the team to complete: the lead-source keys per vertical and per site cannot be derived from the repository alone.
🛡️ Compliance 1
Belgian compliance: partner status and disclosures
Being documented
The central rule: a provider is a partner as soon as ONE of these three signals is true. The API returns a partner offer; the API carries an affiliate link; the site registry carries a REAL affiliate link. It is a non-partner only if NONE of the three is true.
Two traps, and they run in both directions. An affiliate IS a partner: the back office marks affiliates NotPartner because that field means "call-centre partner", so trusting it alone amounts to writing that a genuine partner is not one — that is, a false disclosure on the one sentence legal requires to be exact. And a site registry proves nothing on its own.
Energy · selectra.be
Insurance · selectra.be
Energy · callmepower.be
Insurance · callmepower.be
Energy · mijn-groene-energie.be
Energy · mon-energie-verte.be
The central rule: a provider is a partner as soon as ONE of these three signals is true. The API returns a partner offer; the API carries an affiliate link; the site registry carries a REAL affiliate link. It is a non-partner only if NONE of the three is true.
Two traps, and they run in both directions. An affiliate IS a partner: the back office marks affiliates NotPartner because that field means "call-centre partner", so trusting it alone amounts to writing that a genuine partner is not one — that is, a false disclosure on the one sentence legal requires to be exact. And a site registry proves nothing on its own.
The department convention is departments/belgium-energy/convention/legal-compliance-monetization.md. No compliance skill dedicated to Belgium exists today: the /compliance-article engine is of French jurisdiction.
python scripts/be_provider_check.py {provider}be_provider_check.py measures partner status, region and freshness, and decides nothing.
The country has three regions and three regulators. A single Belgian price is false by construction.
CREG, VREG, CWaPE, BRUGEL, Fluvius, Sibelga, ORES, RESA, IBPT/BIPT. The CRE, RTE, Enedis and ARCEP have no jurisdiction here; the French regulated tariff and Linky have no Belgian equivalent.
⚙️ Infrastructure & Governance 3
Monthly Belgium & Netherlands Content & SEO report
Operational
▸/report-be-nl-monthly [YYYY-MM]
The monthly Content & SEO report for Belgium and the Netherlands, month M against M-1, delivered as a Google Sheet in the layout of the report that used to be filled by hand. It covers CallMePower by category and language, mon-energie-verte.be and mijn-groene-energie.be, the energy comparator, selectra.be, a computed Total organic BE, and selectra.nl.
Pageviews come from Cloudflare Web Analytics with a 'Path contains' filter per column, positions from Search Console, and calls, answered calls and gross sales from the Zoho Analytics Belgian and Dutch views. Every column, path and lead source lives in one config file, so adding a column never means editing the skill.
The report can be run from the 3rd of the following month, once Search Console data is consolidated.
All categories · callmepower.be
Energy · mon-energie-verte.be
Energy · mijn-groene-energie.be
All categories · selectra.be
Energy & Telecom · selectra.nl
/report-be-nl-monthly [YYYY-MM]The monthly Content & SEO report for Belgium and the Netherlands, month M against M-1, delivered as a Google Sheet in the layout of the report that used to be filled by hand. It covers CallMePower by category and language, mon-energie-verte.be and mijn-groene-energie.be, the energy comparator, selectra.be, a computed Total organic BE, and selectra.nl.
Pageviews come from Cloudflare Web Analytics with a 'Path contains' filter per column, positions from Search Console, and calls, answered calls and gross sales from the Zoho Analytics Belgian and Dutch views. Every column, path and lead source lives in one config file, so adding a column never means editing the skill.
The report can be run from the 3rd of the following month, once Search Console data is consolidated.
The Cloudflare token must carry Zone Analytics Read and Account Analytics Read on the Selectra Drupal account. It is filtered by IP address: run from another network, the call is refused until that network's address is added to the token. Any active lead source that no column claims is listed in the report rather than guessed.
python .claude/skills/report-be-nl-monthly/scripts/benelux_report.py plan --month YYYY-MMPrints the four Zoho Analytics calls (Belgian per-category view for M and M-1, Mazout view, Netherlands view) and where to save each result. Each export is checked against the view's own Grand Summary.
python .claude/skills/report-be-nl-monthly/scripts/benelux_report.py pageviews|positions|zoho --month YYYY-MMReads Cloudflare Web Analytics, Search Console and the saved Zoho exports for M and M-1. The zoho step lists every active lead source that no column claims.
python .claude/skills/report-be-nl-monthly/scripts/benelux_report.py build --month YYYY-MMLays everything out in the manual report's layout, with month-over-month percentages, then uploads it to Google Drive as a Google Sheet.
Monthly performance reporting
To be scoped
▸/checkin-monthly
The monthly performance check-in, on one perimeter. Only one Belgian perimeter is outfitted today: selectra.be on /fr/energie, and its file is still marked draft, alongside a file of questions left unanswered.
The three other Belgian sites, and the other trees of selectra.be, have no perimeter at all: no monthly check-in measures them.
Energy · selectra.be
/checkin-monthlyThe monthly performance check-in, on one perimeter. Only one Belgian perimeter is outfitted today: selectra.be on /fr/energie, and its file is still marked draft, alongside a file of questions left unanswered.
The three other Belgian sites, and the other trees of selectra.be, have no perimeter at all: no monthly check-in measures them.
Onboarding a perimeter costs one report-perimeter.json per market, plus the department's report-entities.json and report-page-types.json. No Belgian department has either today. The Belgium & Netherlands monthly report itself is automated separately, by /report-be-nl-monthly.
Belgian internal documentation
Being documented
Belgium has its own internal-page system, on selectra.be: the prose lives in a Markdown file under data/docs-internes/, and a Blade page renders it through a dedicated internal-doc layout whose noindex is HARDCODED, never a prop. An internal page must not be able to become indexable because a caller forgot an argument.
One ficha exists today: how /improve works in Belgium.
Cross-site · selectra.be
Belgium has its own internal-page system, on selectra.be: the prose lives in a Markdown file under data/docs-internes/, and a Blade page renders it through a dedicated internal-doc layout whose noindex is HARDCODED, never a prop. An internal page must not be able to become indexable because a caller forgot an argument.
One ficha exists today: how /improve works in Belgium.
The layout is not shared: it lives in sites/selectra.be/components/layouts/ and touches nothing that already renders in public.
🔀 Migration & Redirects 1
Drupal to CMS migration
Being documented
The move of the Belgian sites off the legacy Drupal onto this CMS, and the debt it leaves behind: callmepower.be still carries its migration batches, its scripts, its list of missing URLs and its directory migration guide; selectra.be carries its click reports and its missing-URL lists.
Every site carries a data/redirects.php that serves the 301s from the catch-all, at zero route cost.
Cross-site · callmepower.be
Cross-site · selectra.be
The move of the Belgian sites off the legacy Drupal onto this CMS, and the debt it leaves behind: callmepower.be still carries its migration batches, its scripts, its list of missing URLs and its directory migration guide; selectra.be carries its click reports and its missing-URL lists.
Every site carries a data/redirects.php that serves the 301s from the catch-all, at zero route cost.
Verified trap: the Drupal image paths /sites/.../files/ are dead and return 404. The assets live on images.selectra.nl and images.selectra.be.