taux-immo-fr — Weekly French mortgage-rate market report
Produce a single self-contained HTML weekly briefing on the French home-loan market: where rates are, who offers what, what the leading indicators say about next week, and what named analysts predict. It is a market panorama, independent of any personal situation — the user supplies nothing about themselves.
When this skill triggers
- "Quel est l'état du marché des taux immobiliers en France ?"
- "Fais-moi le rapport hebdo des taux de crédit immobilier."
- "Quels taux proposent les banques en ce moment / cette semaine ?"
- "Compare les taux entre banques et courtiers."
- "Quelles sont les prévisions de taux immobilier ?"
- "Génère le rapport HTML taux immobilier" / user invokes
/taux-immo-fr.
Do not trigger for — route elsewhere:
- "Combien je peux emprunter ?" / capacité d'emprunt / "avec mes revenus…" → that is capacite-emprunt-fr (personal, HCSF calc). This skill never asks for the user's income, apport, or charges.
- Crédit à la consommation, rachat/regroupement de crédits, prêt pro.
- Taux hors France (Belgique, Suisse, Luxembourg).
- Assurance emprunteur deep-dives, or a specific loan offer review.
Output: one self-contained offline HTML file
The skill writes a single .html to the user's current working directory:
./taux-immo-fr-<week>.html e.g. ./taux-immo-fr-2026-S24.html
That file:
- Renders with vendored, inlined TailwindCSS (compiled, shadcn/ui design tokens) and vendored Chart.js — zero external requests, opens fully offline. No CDN, no build, no server.
- Shows: a fail-loud provenance banner, hero KPI + week-over-week delta, a leading-indicators strip (OAT 10Y / TEC10 / ECB), a 12-month trend chart, a scenario matrix (borrower profile × duration), a per-network comparison chart, editorial cards from lesser-known institutional sources, named-and-dated forecast cards, and a méthodologie/sources section.
- Embeds the full structured data as JSON in
<script id="report-data">— the chart source AND the audit trail (seereferences/data-schema.md).
There is no separate markdown summary; the HTML is the deliverable.
The integrity contract (read first — this is the whole point)
This skill reports current numbers and attributed predictions. A polished report makes a fabricated rate look authoritative. So:
- Every rate carries a source + fetch date in the JSON block. No number without provenance.
- No forecast without a real fetched quote. Never paraphrase "a BNP economist expects 3% by Q4" from memory. No quote → the forecast card is left in its dashed empty state with "pas de citation vérifiable cette semaine".
- Fail loud. When a source 403s or times out, the report SAYS so in the banner and the méthodologie list — it never silently fills the gap with a guess. A visibly stale-but-honest report beats a fresh-looking fabricated one.
- Institutional insight cards shrink when sources fail — an absent card beats an invented "durée moyenne 248 mois".
references/sources.md documents which French sources actually fetch (Empruntis,
ECB, Trading Economics) and which 403 behind Cloudflare (banque-france.fr,
aft.gouv.fr, meilleurtaux.com sometimes), with per-source extraction prompts and
flagged-stale fallback values.
Prerequisites
python3on PATH (forscripts/build_report.py— stdlib only, no pip installs).- WebFetch access. Several sources 403; the skill degrades gracefully per
references/sources.md. - The vendored assets must exist:
assets/report.css,assets/chart.umd.min.js,assets/report.boot.js. They ship with the skill. Only re-runscripts/build_assets.sh(network + Tailwind CLI) if you change the template.
Workflow
Five phases, in order. End each with a one-line status before moving on.
Phase 1 — Research the market (fetch, in parallel)
Fetch the four source clusters from references/sources.md in parallel.
Record fetch status (OK / 403 / fallback) and as_of for each — this populates
the provenance banner. The four clusters:
- Mainstream barèmes (Empruntis ✅, Pretto, Meilleurtaux⚠) — monthly averages for the matrix + comparison.
- Leading indicators (OAT 10Y via Trading Economics ✅, ECB key rates ✅) — the weekly-moving story; always fetch these, they're what make a weekly report non-redundant.
- Institutional / lesser-known (Crédit Logement/CSA, Banque de France production) — the editorial insight cards.
- Forecasts (named courtier economists, bank notes, press) — sourced quotes only.
Optional fan-out: for a thorough weekly sweep you may spawn one research subagent per cluster (Agent tool) so the main context stays clean — each returns structured findings you assemble in Phase 2. Default is inline parallel WebFetch. Either way, the integrity contract holds: a subagent that couldn't fetch a source reports that, and you record it as unavailable — you do not let it improvise.
Phase 2 — Assemble the data object (with provenance)
Build the JSON object matching references/data-schema.md. Copy
references/sample-data.json as your starting template and replace its values
with what you fetched — it has the exact shape and the right units already. For
every field, attach the source + as_of. Compute the derived
spread_oat_bareme_pt. Set provenance.sources_ok / sources_total to the
honest counts and list every failed source in provenance.unavailable +
methodology_sources. Forecasts and insights arrays contain only what you
actually fetched.
Units: put every rate in as a percent number (3.45 = 3.45 %), scalars and
chart arrays alike — see the unit rule in the schema. Deltas are points
(avg_20y_delta_pt) / basis points (oat_10y_delta_bps), signed.
Write the object to a temp file, e.g. /tmp/taux-immo-data.json.
Phase 3 — Build the self-contained file (the JSON is the only thing you author)
You do not hand-edit HTML. scripts/build_report.py renders both the
charts and every text section (hero, indicator tiles, matrix rows, insight
cards, forecast cards, banner counts, méthodologie list) from your JSON, then
inlines the vendored CSS + Chart.js + boot script into one offline HTML. This is
deliberate: it makes "the number in the prose == the number in the JSON" a
mechanical guarantee instead of a hope, and lets the script fail loud rather
than silently ship prototype/empty data.
python3 scripts/build_report.py \
--data /tmp/taux-immo-data.json \
--out ./taux-immo-fr-<week>.html
The script refuses to write (non-zero exit) if:
- a required section (
headline,indicators,matrix,provenance,methodology_sources) is missing — so an incomplete fetch can't produce a half-empty report; - any
{{placeholder}}would survive unfilled — so a forgotten field is a hard error, not a fabricated-looking page; - a vendored asset is missing.
Empty insights / forecasts arrays are allowed and render as explicit
honest empty-state cards ("aucune citation vérifiable cette semaine") — never as
invented content. FR formatting (decimal comma "3,42 %", arrows on deltas) is
handled by the renderers; you only supply correct numbers in the JSON.
Phase 4 — Verify offline + report
Confirm the output is genuinely self-contained before handing it over:
grep -niE '<(script|link|img|source)[^>]*(src|href)=["'"'"']https?://' ./taux-immo-fr-<week>.html \
&& echo "FAIL: external load found" || echo "PASS: fully offline"
Tell the user the file path, the headline rate + week-over-week move, how many sources were verified vs. unavailable, and that the file opens offline. Then emit the Step Completion Report below.
Acceptance Criteria
The run is done when all hold (verify each before reporting PASS):
- A single
./taux-immo-fr-<week>.htmlis written;build_report.pyexited 0. - The offline grep in Phase 4 prints
PASS: fully offline(0 external loads). - Every rate in
<script id="report-data">has asource+as_of;provenance.sources_ok/sources_totalmatch the honest fetch counts. - No
{{placeholder}}survives in the output (the build asserts this). forecasts/insightscontain only fetched, attributed items — or render the explicit honest empty state, never invented content.
Expected output
A self-contained HTML report plus the terminal Step Completion Report shown below — e.g. Sources fetched: √ 6/8, Self-contained offline: √ grep clean, Result: PASS. The HTML file opens in a browser with charts rendered and zero network requests. See the Step Completion Report block at the end for the exact shape.
Edge Cases
Inputs the skill rejects or handles specially:
- WebFetch 403 / timeout — retry once with the secondary URL in
sources.md. Still failing → use the flagged-stale fallback, setsource_fallback: true, and surface it in the banner. Never present a fallback as a fresh fetch. - No forecast quotes found — ship empty forecast cards, do not invent. This is correct behavior, not a failure.
build_report.pynon-zero exit — read stderr; it names the missing asset or placeholder. Fix that input; never hand-edit the output to paper over it.- External-ref warning from the script — an asset was linked instead of inlined. Inline it; the offline guarantee is non-negotiable.
- Charts blank in browser — almost always a unit mismatch in
trend/banks(decimal vs percent). Make both percent. See the schema unit rule. - "rate field outside the sane percent band" exit — you passed a decimal
(
0.0345) or basis points (345) where a percent number (3.45) was required. Fix the unit in the JSON; the guard exists so a 100×-wrong rate never ships.
Step Completion Report
◆ Weekly Taux-Immo Report (FR market panorama)
··································································
Sources fetched: √ N/M (list any 403/fallback)
Provenance complete: √ every rate has source + as_of
Forecasts sourced: √ all named+dated (or empty, none invented)
Self-contained offline: √ grep clean — 0 external loads
Report written: √ ./taux-immo-fr-<week>.html
____________________________
Result: PASS | PARTIAL (stale sources) | FAIL
Reference files
references/sources.md— the four source clusters, working vs 403 URLs, extraction prompts, flagged-stale fallbacks, the integrity contract.references/data-schema.md— the auditable JSON block; unit rule; provenance.references/sample-data.json— a complete, correctly-shaped example to copy and adapt (right keys, right units). Start here in Phase 2.references/html-template.html— the static report shell. Asset markers (/*__REPORT_CSS__*/,/*__CHART_JS__*/,/*__REPORT_BOOT__*/,<!--__REPORT_DATA__-->) +{{TOKEN}}text placeholders the script fills from JSON.scripts/build_report.py— renders all text + charts from JSON and inlines vendored assets → offline HTML (runtime). Fails loud on missing data / unfilled tokens.scripts/build_assets.sh— re-vendors assets (build-time only; network + Tailwind CLI).