← library
skill📊 Dashboards & analyticsv1 · published 2026-10-22 · updated 2026-11-03

Build my weekly numbers

Builds a one-file weekly numbers page that runs only in your browser. Paste your newsletter sends and LinkedIn posts as CSV and it shows each newsletter's latest open and click rate against its own average, a small chart per newsletter, LinkedIn last week against the week before, the top post, and three lines on what moved. Use when someone in marketing or communications rebuilds the same weekly report by hand and wants a tool that does it from an export in seconds.

By Uplift Duo

Run it as a prompt

Paste this into any AI agent, or fetch it: curl -s https://uplift.page/api/v1/prompts/build-my-weekly-numbers/raw

prompt.md
# Build my weekly numbers

Every week I copy numbers out of exports into a report. Build me a small page that does it: I paste the exports in, and it tells me what moved. It runs only on my device, so nothing I paste goes anywhere.

## Before you start

Ask me one question, then stop and wait: "Besides newsletter sends and LinkedIn posts, is there one more number your weekly report always has? Name it and its CSV columns, or say 'use the sample'."

If I name one, add a third paste box for it with the same treatment as the newsletters (latest value against the average of the earlier rows), and tell me in one line what you added. If I say "use the sample", build exactly what's below and nothing more.

## Steps

1. **Build one HTML file** with everything inline: plain HTML, CSS and JavaScript. No libraries, no chart packages, no fonts or scripts from the internet, and no network requests of any kind. It must work with wifi off. Don't save anything to the browser's storage. Draw charts with inline SVG. Keep the code plain: one short function per job (read the CSV, work out a newsletter, work out LinkedIn, draw a chart). Before you hand it over, read the script through once for unmatched brackets or quotes, because one typo stops every button. If this app can run code, check the script with it (for example `node --check`).
2. **Read the CSVs.** The first row is the header; match columns by name, in any order and any case. Allow quoted fields with commas inside. Skip any row whose number columns aren't whole numbers (blank, "n/a", text), and say under the results how many rows were skipped and from which box. Commas inside numbers ("18,240") count as numbers.
3. **Newsletters** (columns `newsletter, send_date, delivered, opens, clicks`). For each newsletter, in the order they first appear:
   - the **latest send** is the row with the latest `send_date`;
   - **open rate** = opens ÷ delivered and **click rate** = clicks ÷ delivered, shown as percentages with one decimal (39.0%);
   - the **average** is the plain mean of that newsletter's open rates (and click rates) on its earlier sends, not a total divided by a total;
   - show the latest open rate, its average, and the word **up** or **down** with an arrow (▲ up, ▼ down), then the same for clicks;
   - a small SVG line chart of that newsletter's open rate across all its sends, oldest on the left, the latest point marked.
   A newsletter with only one send shows its rates and "no earlier sends to compare".
4. **LinkedIn** (columns `date, post, impressions, clicks, reactions`). **Last week** is the 7 days ending on the latest date in the file, counting that day; **the week before** is the 7 days before that. Show impressions and clicks for each week, with thousands separators (18,630), whether each went up or down, and the **top post** of last week by clicks, by its title.
5. **What moved.** Three short plain-English lines under the heading "What moved", each naming the newsletter or LinkedIn and the change, biggest first. Facts from the numbers only; no guesses about why.
6. **The screen**, in this order: the title "Weekly numbers"; a box labeled "Newsletter sends (CSV)"; a box labeled "LinkedIn posts (CSV)"; a **Show my numbers** button; a **Load sample** button; the results: one card per newsletter side by side (they wrap to one column on a phone), then the LinkedIn card, then What moved. At the very top, put a line that reads "Not running: open this file in a browser such as Chrome, Safari or Edge. Previews and text editors don't run the buttons." The script hides that line as soon as it loads.
   **Load sample** fills both boxes with exactly this made-up data and shows the numbers at once.

   Newsletter sends:

   ```
   newsletter,send_date,delivered,opens,clicks
   Recycling Weekly,2026-09-15,18240,6384,912
   Recycling Weekly,2026-09-22,18310,6226,860
   Recycling Weekly,2026-09-29,18402,6624,957
   Recycling Weekly,2026-10-06,18455,6460,886
   Recycling Weekly,2026-10-13,18520,7223,1185
   Plastics Brief,2026-09-16,12105,4963,726
   Plastics Brief,2026-09-23,12160,5107,778
   Plastics Brief,2026-09-30,12201,5003,744
   Plastics Brief,2026-10-07,12248,5266,796
   Plastics Brief,2026-10-14,12290,4548,590
   Electronics Digest,2026-09-17,9870,3455,434
   Electronics Digest,2026-09-24,9902,3664,475
   Electronics Digest,2026-10-01,9935,3378,417
   Electronics Digest,2026-10-08,9961,3586,458
   Electronics Digest,2026-10-15,10004,3602,510
   ```

   LinkedIn posts:

   ```
   date,post,impressions,clicks,reactions
   2026-10-02,Call for speakers is open,4210,96,58
   2026-10-03,Plastics Brief: bale prices this week,3120,71,34
   2026-10-06,Photo recap from the plant tour,5480,63,141
   2026-10-08,Early-bird registration ends Friday,3890,112,41
   2026-10-09,Five charts on battery collection,6020,154,88
   2026-10-10,Meet the new sponsor lounge,2750,38,29
   2026-10-13,Webinar replay: sorting robots,4980,131,63
   2026-10-15,Award finalists announced,7340,205,212
   2026-10-16,Electronics Digest: a recycler opens a second site,3560,89,37
   ```

   Check your work against the sample before you hand the file over: Recycling Weekly's latest open rate is 39.0% against an average of 35.0% (up), Plastics Brief's is 37.0% against 41.7% (down), LinkedIn last week had 18,630 impressions and 463 clicks against 18,510 and 400 the week before, and the top post is "Award finalists announced". If any of those come out different, fix the math before you hand it over.
1. **Hand it over.** Give me the file as a download if this app can make one; otherwise show the code. Then tell me how to open it, using only the lines that fit my device and this app:
   - If this app has a preview where buttons work (a canvas, artifact or preview pane), use it.
   - On a computer: save it as `weekly-numbers.html` and open it in Chrome, Safari or Edge. If you copy the code into a file yourself, use a plain-text editor; on a Mac, in TextEdit choose Format, then Make Plain Text, before you save.
   - On a phone: a saved file opens as a preview, and previews don't run buttons. Use this app's preview, or open the file on a computer.
   Then say, word for word: "Press Load sample. If the numbers match the ones I checked, it works. Next week, export your sends and posts as CSV, paste them in, and press Show my numbers."
2. **End with a reminder** that the page only knows what's in the export: say which numbers it can't see (unsubscribes, revenue, anything not in the CSV), and suggest running the Make it pass prompt next to test it with tricky exports.

## Branding

Style it in my company's colors if I've shared a brand guide. Otherwise use the default look (Uplift Duo): page `#FAF9F6`, text `#1A1A1A`, buttons `#E85D04` with white text, white cards with a 1px `#E0DDD5` border, up in green `#1F7A4D`, down in red `#B42318`. System fonts only, so it works offline. Never make up a palette, and don't put a company name on the page.

## Rules

- No network requests, external files or storage. If something I ask for would need the internet (a live API, a login), say so and leave it out; the export is the connection.
- Never invent a number. Everything on the page comes from the pasted CSVs.
- Keep it to one file I can email to a coworker.

Install it as a skill

Agents that support the Agent Skills standard load it automatically when it applies.

download
curl -fsSL https://uplift.page/p/build-my-weekly-numbers/SKILL.md --create-dirs -o .agents/skills/build-my-weekly-numbers/SKILL.md
or from any MCP client
MCP server: https://uplift.page/mcp
Tool: pull_skill  {"slug": "build-my-weekly-numbers"}

The full skill

Every week I copy numbers out of exports into a report. Build me a small page that does it: I paste the exports in, and it tells me what moved. It runs only on my device, so nothing I paste goes anywhere.

Before you start

Ask me one question, then stop and wait: "Besides newsletter sends and LinkedIn posts, is there one more number your weekly report always has? Name it and its CSV columns, or say 'use the sample'."

If I name one, add a third paste box for it with the same treatment as the newsletters (latest value against the average of the earlier rows), and tell me in one line what you added. If I say "use the sample", build exactly what's below and nothing more.

Steps

  1. Build one HTML file with everything inline: plain HTML, CSS and JavaScript. No libraries, no chart packages, no fonts or scripts from the internet, and no network requests of any kind. It must work with wifi off. Don't save anything to the browser's storage. Draw charts with inline SVG. Keep the code plain: one short function per job (read the CSV, work out a newsletter, work out LinkedIn, draw a chart). Before you hand it over, read the script through once for unmatched brackets or quotes, because one typo stops every button. If this app can run code, check the script with it (for example node --check).

  2. Read the CSVs. The first row is the header; match columns by name, in any order and any case. Allow quoted fields with commas inside. Skip any row whose number columns aren't whole numbers (blank, "n/a", text), and say under the results how many rows were skipped and from which box. Commas inside numbers ("18,240") count as numbers.

  3. Newsletters (columns newsletter, send_date, delivered, opens, clicks). For each newsletter, in the order they first appear:

    • the latest send is the row with the latest send_date;
    • open rate = opens ÷ delivered and click rate = clicks ÷ delivered, shown as percentages with one decimal (39.0%);
    • the average is the plain mean of that newsletter's open rates (and click rates) on its earlier sends, not a total divided by a total;
    • show the latest open rate, its average, and the word up or down with an arrow (▲ up, ▼ down), then the same for clicks;
    • a small SVG line chart of that newsletter's open rate across all its sends, oldest on the left, the latest point marked. A newsletter with only one send shows its rates and "no earlier sends to compare".
  4. LinkedIn (columns date, post, impressions, clicks, reactions). Last week is the 7 days ending on the latest date in the file, counting that day; the week before is the 7 days before that. Show impressions and clicks for each week, with thousands separators (18,630), whether each went up or down, and the top post of last week by clicks, by its title.

  5. What moved. Three short plain-English lines under the heading "What moved", each naming the newsletter or LinkedIn and the change, biggest first. Facts from the numbers only; no guesses about why.

  6. The screen, in this order: the title "Weekly numbers"; a box labeled "Newsletter sends (CSV)"; a box labeled "LinkedIn posts (CSV)"; a Show my numbers button; a Load sample button; the results: one card per newsletter side by side (they wrap to one column on a phone), then the LinkedIn card, then What moved. At the very top, put a line that reads "Not running: open this file in a browser such as Chrome, Safari or Edge. Previews and text editors don't run the buttons." The script hides that line as soon as it loads. Load sample fills both boxes with exactly this made-up data and shows the numbers at once.

    Newsletter sends:

    newsletter,send_date,delivered,opens,clicks
    Recycling Weekly,2026-09-15,18240,6384,912
    Recycling Weekly,2026-09-22,18310,6226,860
    Recycling Weekly,2026-09-29,18402,6624,957
    Recycling Weekly,2026-10-06,18455,6460,886
    Recycling Weekly,2026-10-13,18520,7223,1185
    Plastics Brief,2026-09-16,12105,4963,726
    Plastics Brief,2026-09-23,12160,5107,778
    Plastics Brief,2026-09-30,12201,5003,744
    Plastics Brief,2026-10-07,12248,5266,796
    Plastics Brief,2026-10-14,12290,4548,590
    Electronics Digest,2026-09-17,9870,3455,434
    Electronics Digest,2026-09-24,9902,3664,475
    Electronics Digest,2026-10-01,9935,3378,417
    Electronics Digest,2026-10-08,9961,3586,458
    Electronics Digest,2026-10-15,10004,3602,510
    

    LinkedIn posts:

    date,post,impressions,clicks,reactions
    2026-10-02,Call for speakers is open,4210,96,58
    2026-10-03,Plastics Brief: bale prices this week,3120,71,34
    2026-10-06,Photo recap from the plant tour,5480,63,141
    2026-10-08,Early-bird registration ends Friday,3890,112,41
    2026-10-09,Five charts on battery collection,6020,154,88
    2026-10-10,Meet the new sponsor lounge,2750,38,29
    2026-10-13,Webinar replay: sorting robots,4980,131,63
    2026-10-15,Award finalists announced,7340,205,212
    2026-10-16,Electronics Digest: a recycler opens a second site,3560,89,37
    

    Check your work against the sample before you hand the file over: Recycling Weekly's latest open rate is 39.0% against an average of 35.0% (up), Plastics Brief's is 37.0% against 41.7% (down), LinkedIn last week had 18,630 impressions and 463 clicks against 18,510 and 400 the week before, and the top post is "Award finalists announced". If any of those come out different, fix the math before you hand it over.

  7. Hand it over. Give me the file as a download if this app can make one; otherwise show the code. Then tell me how to open it, using only the lines that fit my device and this app:

    • If this app has a preview where buttons work (a canvas, artifact or preview pane), use it.
    • On a computer: save it as weekly-numbers.html and open it in Chrome, Safari or Edge. If you copy the code into a file yourself, use a plain-text editor; on a Mac, in TextEdit choose Format, then Make Plain Text, before you save.
    • On a phone: a saved file opens as a preview, and previews don't run buttons. Use this app's preview, or open the file on a computer. Then say, word for word: "Press Load sample. If the numbers match the ones I checked, it works. Next week, export your sends and posts as CSV, paste them in, and press Show my numbers."
  8. End with a reminder that the page only knows what's in the export: say which numbers it can't see (unsubscribes, revenue, anything not in the CSV), and suggest running the Make it pass prompt next to test it with tricky exports.

Branding

Style it in my company's colors if I've shared a brand guide. Otherwise use the default look (Uplift Duo): page #FAF9F6, text #1A1A1A, buttons #E85D04 with white text, white cards with a 1px #E0DDD5 border, up in green #1F7A4D, down in red #B42318. System fonts only, so it works offline. Never make up a palette, and don't put a company name on the page.

Rules

  • No network requests, external files or storage. If something I ask for would need the internet (a live API, a login), say so and leave it out; the export is the connection.
  • Never invent a number. Everything on the page comes from the pasted CSVs.
  • Keep it to one file I can email to a coworker.

Served from the uplift.page library and refreshed within 5 minutes of every update.