From granola-pack
Build automated pipelines from Granola meeting notes to GitHub Issues, Linear tasks, Slack notifications, and documentation updates using Zapier and GitHub Actions. Trigger: "granola CI", "granola automation pipeline", "granola to github", "granola to linear", "meeting notes automation".
npx claudepluginhub flight505/skill-forge --plugin granola-packThis skill is limited to using the following tools:
Build automated pipelines that process Granola meeting notes into development artifacts: GitHub Issues from action items, Linear tasks with team routing, Slack digests for stakeholders, and meeting logs in your repository. Uses Zapier as the middleware between Granola and dev tools.
Guides Next.js Cache Components and Partial Prerendering (PPR): 'use cache' directives, cacheLife(), cacheTag(), revalidateTag() for caching, invalidation, static/dynamic optimization. Auto-activates on cacheComponents: true.
Guides building MCP servers enabling LLMs to interact with external services via tools. Covers best practices, TypeScript/Node (MCP SDK), Python (FastMCP).
Share bugs, ideas, or general feedback.
Build automated pipelines that process Granola meeting notes into development artifacts: GitHub Issues from action items, Linear tasks with team routing, Slack digests for stakeholders, and meeting logs in your repository. Uses Zapier as the middleware between Granola and dev tools.
# Pipeline: Granola → Zapier → GitHub + Slack + Linear
Trigger:
App: Granola
Event: Note Added to Granola Folder
Folder: "Engineering" # Only process engineering meetings
Add a Code by Zapier step (JavaScript) to extract action items:
// Zapier Code Step — Extract action items from Granola note
const noteContent = inputData.note_content || '';
const meetingTitle = inputData.title || 'Untitled Meeting';
const meetingDate = inputData.calendar_event_datetime || new Date().toISOString();
// Extract action items: matches "- [ ] @person: task" or "- [ ] task"
const actionRegex = /- \[ \] @?(\w+):?\s+(.+)/g;
const actions = [];
let match;
while ((match = actionRegex.exec(noteContent)) !== null) {
actions.push({
assignee: match[1],
task: match[2].trim(),
meeting: meetingTitle,
date: meetingDate.split('T')[0],
});
}
// Extract decisions: lines starting with "- " under "## Decisions" or "## Key Decisions"
const decisionSection = noteContent.match(/## (?:Key )?Decisions\n([\s\S]*?)(?=\n##|$)/);
const decisions = decisionSection
? decisionSection[1].split('\n').filter(l => l.startsWith('- ')).map(l => l.replace('- ', ''))
: [];
output = [{
action_count: actions.length,
actions: JSON.stringify(actions),
decisions: decisions.join('; '),
meeting_title: meetingTitle,
meeting_date: meetingDate,
}];
# For each action item, create a GitHub issue
Action:
App: GitHub
Event: Create Issue
Repository: "your-org/your-repo"
Title: "Meeting Action: {{task}} [{{date}}]"
Body: |
## Context
From meeting: **{{meeting}}** on {{date}}
## Task
{{task}}
## Assigned To
@{{assignee}}
---
*Auto-created from Granola meeting notes*
Labels: "meeting-action"
Assignee: "{{assignee}}" # Must match GitHub username
Create a workflow triggered by Zapier via repository_dispatch:
# .github/workflows/meeting-log.yml
name: Update Meeting Log
on:
repository_dispatch:
types: [granola-meeting]
jobs:
update-log:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Append to meeting log
run: |
MEETING_TITLE="${{ github.event.client_payload.title }}"
MEETING_DATE="${{ github.event.client_payload.date }}"
DECISIONS="${{ github.event.client_payload.decisions }}"
ACTION_COUNT="${{ github.event.client_payload.action_count }}"
mkdir -p docs/meetings
cat >> docs/meetings/log.md << EOF
## ${MEETING_DATE} — ${MEETING_TITLE}
- **Decisions:** ${DECISIONS}
- **Action items created:** ${ACTION_COUNT}
- **Source:** Granola AI
EOF
- name: Commit and push
run: |
git config user.name "Granola Bot"
git config user.email "bot@granola.ai"
git add docs/meetings/log.md
git commit -m "docs: meeting log — ${MEETING_DATE}" || echo "No changes"
git push
Trigger from Zapier using the Webhooks action:
Action:
App: Webhooks by Zapier
Event: POST
URL: https://api.github.com/repos/your-org/your-repo/dispatches
Headers:
Authorization: "Bearer {{github_pat}}"
Accept: "application/vnd.github.v3+json"
Body:
event_type: "granola-meeting"
client_payload:
title: "{{meeting_title}}"
date: "{{meeting_date}}"
decisions: "{{decisions}}"
action_count: "{{action_count}}"
Action:
App: Linear
Event: Create Issue
Team: Engineering
Title: "{{task}}"
Description: "From meeting: {{meeting}} ({{date}})\n\nAssigned: @{{assignee}}"
Label: "meeting-action"
Priority: "Medium"
Action:
App: Slack
Event: Send Channel Message
Channel: "#engineering-meetings"
Message: |
:memo: *Meeting Notes Ready:* {{meeting_title}}
:calendar: {{meeting_date}}
*Decisions:*
{{decisions}}
*Action Items Created:* {{action_count}}
:point_right: Check Linear/GitHub for assigned tasks
[View full notes in Granola]
Meeting ends → Granola enhances notes
→ Note added to "Engineering" folder
→ Zapier triggers
├→ Parse action items (Code step)
├→ Create GitHub Issues (per action item)
├→ Trigger GitHub Actions (update meeting log)
├→ Create Linear tasks (per action item)
└→ Post Slack summary (#engineering-meetings)
| Error | Cause | Fix |
|---|---|---|
| Zapier trigger not firing | Note not in the configured folder | Verify folder name matches exactly |
| GitHub issue creation fails | PAT expired or insufficient scope | Regenerate PAT with repo scope |
| Action items not parsed | Note format doesn't match regex | Adjust regex for your template's action item format |
| Linear API error | Team name mismatch | Use Linear team ID instead of name |
| Slack message empty | Note still processing | Add 2-minute delay as first Zap step |
Proceed to granola-deploy-integration for native app integration setup.