A Google Apps Script add-on that automatically transforms Google Meet transcripts (generated by Gemini) into Linear issues, with a manager approval step before any issue is created.
Google Meet ends
↓
Gemini generates meeting notes → saved to Google Drive
↓
Apps Script finds the transcript
↓
Gemini (via Requesty) extracts action items as structured JSON
↓
Manager receives an approval email with one button per issue
↓
Manager approves individual issues (or all at once)
↓
Issues are created in Linear via GraphQL API
- Automatic trigger — polls Google Calendar every 5 minutes to detect ended Meet sessions
- Smart transcript detection — searches Drive for Gemini-generated notes matching today's date and meeting title, with up to 3 retries (covers overruns and Google's processing delay)
- Selective activation — only processes meetings where a specific email address is present among the participants
- AI extraction — uses Gemini via Requesty to extract title, description, assignee, priority, and due date for each action item
- Granular approval — the manager can approve issues one by one, approve all at once, or cancel everything
- Automatic assignee resolution — cross-references Calendar participants with Linear workspace members by email, then passes the mapping to Gemini so each action item gets assigned to the correct Linear user ID automatically. Matching works by full name, first name, or email address
├── Config.gs # API keys and global constants
├── Trigger.gs # Calendar polling, transcript search, retry logic
├── AIProcessor.gs # Gemini prompt and JSON extraction via Requesty
├── Approval.gs # Approval email with per-issue buttons
├── LinearAPI.gs # Linear GraphQL mutation and doGet web app handler
└── appsscript.json # Manifest with scopes and add-on config
- A Google Workspace account
- A Requesty account and API key
- A Linear account with API access
- Google Meet with Gemini notes enabled (notes must be saved to Drive)
- Go to script.google.com and create a new project
- Create the following files:
Config.gs,Trigger.gs,AIProcessor.gs,Approval.gs,LinearAPI.gs - Copy the code from this repository into each file
In the Apps Script editor, go to Project Settings (⚙️) → Show appsscript.json, then replace its content with:
{
"timeZone": "Europe/Rome",
"dependencies": {
"enabledAdvancedServices": [
{ "userSymbol": "Drive", "version": "v3", "serviceId": "drive" },
{ "userSymbol": "Gmail", "version": "v1", "serviceId": "gmail" },
{ "userSymbol": "Calendar", "version": "v3", "serviceId": "calendar" }
]
},
"exceptionLogging": "STACKDRIVER",
"runtimeVersion": "V8",
"oauthScopes": [
"https://www.googleapis.com/auth/drive.readonly",
"https://www.googleapis.com/auth/gmail.send",
"https://www.googleapis.com/auth/calendar.readonly",
"https://www.googleapis.com/auth/script.external_request",
"https://www.googleapis.com/auth/script.scriptapp"
],
"addOns": {
"common": {
"name": "Meet → Linear Automation",
"logoUrl": "https://www.gstatic.com/images/branding/product/1x/apps_script_48dp.png"
}
},
"webapp": {
"executeAs": "USER_DEPLOYING",
"access": "DOMAIN"
}
}Go to Project Settings (⚙️) → Script properties and add the following keys:
| Key | Description |
|---|---|
REQUESTY_API_KEY |
Your Requesty API key |
REQUESTY_MODEL |
Model to use via Requesty (e.g. google/gemini-2.0-flash). Falls back to google/gemini-2.0-flash if not set |
LINEAR_API_KEY |
Your Linear personal API key (lin_api_...) |
TEAM_ID |
Your Linear team ID (see below) |
MANAGER_EMAIL |
Email address that will receive approval requests |
TRIGGER_EMAIL |
The meeting participant whose presence activates the flow |
Run this query against the Linear API (e.g. with curl or any GraphQL client):
curl -X POST https://api.linear.app/graphql \
-H "Authorization: YOUR_LINEAR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"query":"{ teams { nodes { id name } } }"}'Copy the id of your team and save it as TEAM_ID.
The approval email links rely on a web app endpoint (doGet):
- Click Deploy → New Deployment
- Select type: Web App
- Execute as: Me
- Who has access: Anyone with a Google Account (or limit to your domain)
- Click Deploy and copy the web app URL
⚠️ Every time you modify the code, you must create a new version under Deploy → Manage Deployments for changes to take effect.
Run setupTrigger() once from the Apps Script editor. This installs a time-based trigger that polls Calendar every 5 minutes. You can verify it is active under Triggers (⏰) in the left sidebar.
Once set up, the flow runs automatically:
- A Google Meet ends with
TRIGGER_EMAILamong the participants - Gemini generates the meeting notes and saves them to Drive
- After ~10 minutes (to allow for overruns and processing delay), the script finds the transcript
- An approval email is sent to
MANAGER_EMAIL - The manager clicks Approve next to each issue they want to create, or Approve all
- Issues appear in Linear instantly
You can test the full flow manually without waiting for a meeting to end:
function testFullFlow() {
const today = Utilities.formatDate(new Date(), "Europe/Rome", "yyyy/MM/dd");
const files = DriveApp.searchFiles('title contains "Gemini"');
while (files.hasNext()) {
const file = files.next();
const name = file.getName();
if (name.includes(today)) {
const url = "https://www.googleapis.com/drive/v3/files/" + file.getId() + "/export?mimeType=text/plain";
const res = UrlFetchApp.fetch(url, {
headers: { "Authorization": "Bearer " + ScriptApp.getOAuthToken() }
});
const transcript = res.getContentText();
console.log("✅ Transcript found:", name);
const items = extractActionItems(transcript);
console.log("📋 Extracted items:", JSON.stringify(items, null, 2));
sendApprovalEmail(items, MANAGER_EMAIL, name);
console.log("📧 Email sent to:", MANAGER_EMAIL);
return;
}
}
console.log("❌ No Gemini notes found for today");
}| Gemini output | Linear priority |
|---|---|
urgent |
1 — Urgent |
high |
2 — High |
medium |
3 — Medium |
low |
4 — Low |
- Approval links expire after 1 hour (configurable via
CacheServiceTTL) - The script retries transcript detection up to 3 times (10 min + 5 min + 5 min = up to 20 minutes after meeting end)
- Gemini notes must be saved to the same Google Drive account running the script
- The trigger activates only for events where
TRIGGER_EMAILis among the participants — no Meet link check is performed since Google Calendar does not always populate the location field - Assignee matching uses three keys per user: full name, first name, and email — so Gemini can resolve mentions to the same Linear user ID
MIT