Draft meeting agendas from past notes
Generate Northwind meeting agendas from history and stated goals — no blank-page syndrome.
Published Oct 18, 2025
The hardest part of a recurring Northwind meeting is starting the agenda. The context is all there — last week’s notes list what was decided, what stalled, and what got pushed — but turning that into a fresh agenda means re-reading everything and remembering which threads are still open. So the agenda gets thrown together five minutes before the call, and the same items slip week after week.
This script reads the running notes Doc, takes a short list of goals for the next session, and asks Claude to draft an agenda that carries forward the open threads. It appends the draft to the bottom of the same Doc, so the agenda and the history live together.
What you’ll need
- A Google Doc holding your running meeting notes — the script reads the most recent text and appends the new agenda to the end.
- A short list of goals for the next session, set in the
MEETING_GOALSconstant (or passed in from a menu prompt). - An Anthropic API key saved as
ANTHROPIC_API_KEYin Script Properties — see Store API keys and secrets securely.
The script
// The running meeting-notes Doc. The script reads it and appends to it.
const NOTES_DOC_ID = '1abcNotesDocId';
// What the next session should focus on. Edit this before each run.
const MEETING_GOALS = 'Q2 launch timeline, hiring plan, support backlog';
// How much of the notes Doc to send. The most recent text matters most,
// so we read from the end — see "Watch out for".
const CONTEXT_CHARS = 6000;
/**
* Reads the recent meeting notes, asks Claude to draft an agenda for
* the next session, and appends that agenda to the bottom of the Doc.
*/
function appendNextAgenda() {
const doc = DocumentApp.openById(NOTES_DOC_ID);
const body = doc.getBody();
// 1. Read the most recent slice of notes for context.
const draft = draftAgenda(NOTES_DOC_ID, MEETING_GOALS);
if (!draft) {
Logger.log('No agenda returned — nothing to append.');
return;
}
// 2. Append the agenda under a dated heading so it is easy to find.
const today = Utilities.formatDate(
new Date(), Session.getScriptTimeZone(), 'yyyy-MM-dd');
body.appendParagraph('Agenda — ' + today)
.setHeading(DocumentApp.ParagraphHeading.HEADING2);
body.appendParagraph(draft);
Logger.log('Appended an agenda dated ' + today + '.');
}
/**
* Asks Claude to draft a numbered agenda from the tail of the notes
* Doc, focused on the goals it is given.
*/
function draftAgenda(notesDocId, goals) {
// Read the END of the notes — the most recent session matters most.
const full = DocumentApp.openById(notesDocId).getBody().getText();
const past = full.slice(-CONTEXT_CHARS);
if (!past.trim()) {
Logger.log('Notes Doc is empty — cannot draft from history.');
return '';
}
const prompt =
'Given these recent Northwind meeting notes:\n' + past +
'\n\nDraft an agenda for the next session focused on: ' + goals + '. ' +
'Carry forward any unresolved items from the notes. ' +
'Return as a numbered list, each item with a short time estimate.';
return callClaude(prompt, 'claude-sonnet-4-6', 600);
}
/**
* Minimal Anthropic API call. The key lives in Script Properties — it
* is never pasted into the code.
*/
function callClaude(prompt, model = 'claude-haiku-4-5-20251001', maxTokens = 400) {
const key = PropertiesService.getScriptProperties()
.getProperty('ANTHROPIC_API_KEY');
const res = UrlFetchApp.fetch('https://api.anthropic.com/v1/messages', {
method: 'post',
contentType: 'application/json',
headers: { 'x-api-key': key, 'anthropic-version': '2023-06-01' },
payload: JSON.stringify({
model,
max_tokens: maxTokens,
messages: [{ role: 'user', content: prompt }],
}),
muteHttpExceptions: true,
});
return JSON.parse(res.getContentText()).content[0].text.trim();
}
How it works
appendNextAgendaopens the notes Doc and callsdraftAgendawith the goals set inMEETING_GOALS.draftAgendareads the Doc’s full text and keeps only the lastCONTEXT_CHARScharacters — the most recent session, which is the part that actually predicts the next agenda.- If that slice is empty, it logs a message and stops — there is nothing to draft from.
- It builds a prompt that includes the recent notes and the goals, and asks Claude to carry forward any unresolved items and add a time estimate per line.
- It calls Claude Sonnet, which handles the reasoning needed to spot which threads are still open.
- Back in
appendNextAgenda, the draft is appended under a datedHeading 2, so the agenda and its source notes stay in one Doc.
Example run
Say the bottom of the notes Doc reads:
2025-10-11 — Agreed the Q2 launch slips two weeks. Hiring: still need a second designer; JD not written. Support backlog hit 40 tickets — no owner assigned yet.
With MEETING_GOALS set to Q2 launch timeline, hiring plan, support backlog,
a run appends:
Agenda — 2025-10-18
- Confirm the revised Q2 launch date and lock dependencies (15 min)
- Designer hire: assign an owner to write the JD this week (10 min)
- Support backlog: pick an owner, agree a target to clear 40 tickets (15 min)
- Quick wins and blockers round-table (10 min)
Every open thread from last week is on the agenda — nothing slips because someone forgot.
Run it
This is a once-per-meeting job, so run it by hand before each session:
- Update
MEETING_GOALSwith what the next session should cover. - In the Apps Script editor, select
appendNextAgendaand click Run. - Approve the authorisation prompt the first time.
- Open the notes Doc — the new agenda is at the bottom under a dated heading.
To make it self-serve, add a custom menu that prompts for goals at run time:
function onOpen() {
DocumentApp.getUi()
.createMenu('Meeting tools')
.addItem('Draft next agenda', 'appendNextAgenda')
.addToUi();
}
Watch out for
- It drafts from the end of the Doc. If your most recent notes are at the top,
read the start instead with
.slice(0, CONTEXT_CHARS)— otherwise Claude works from stale context. - The agenda is a starting point, not a final one. Always read it before the meeting: Claude can carry forward an item that was actually closed, or miss one phrased vaguely.
- It appends, it never overwrites. Run it twice and you get two agendas — fine, but delete the stale one so the Doc does not sprawl.
- Meeting notes can be sensitive. The recent text is sent to the API, so keep
anything confidential — salaries, personnel issues — out of the notes Doc, or
shorten
CONTEXT_CHARSso it stays out of the prompt.
Related
Generate and test email subject lines
A/B test AI-written Northwind subject lines for open rate — outputs ranked by past performance.
Updated Mar 3, 2026
Build retrieval-augmented Q&A over your data
Answer Northwind questions grounded in your own Sheet data — pass relevant rows as context.
Updated Feb 27, 2026
Build an AI weekly-report narrator
Turn Northwind metrics into a written executive summary — numbers in, prose out.
Updated Feb 23, 2026
Build a multi-step AI agent workflow
Chain Claude prompts to complete a Northwind task end to end — research → draft → critique → finalise.
Updated Feb 11, 2026
Adapt marketing copy per region
Localise Northwind tone and references by market with AI — same message, regional flavour.
Updated Jan 30, 2026