DEV Community

Cover image for NotebookLM Enhancer
Cesar Castillo
Cesar Castillo

Posted on

NotebookLM Enhancer

GitHub Copilot CLI Challenge Submission

Submission for: GitHub Copilot CLI Challenge (February 2026)
Author: Cesar Castillo
Repository: https://github.com/CGCM070/NotebookLM_Enhancer


From Chaos to Order

  • Building a Chrome Extension That Finally Organizes NotebookLM

What I Built

A Chrome extension that transforms NotebookLM's chaotic sidebar into a beautifully organized folder system, because 47 research notes shouldn't look like a pile of digital laundry.

The Problem That Drove Me Crazy

If you've used NotebookLM, you know it's magical for research. Upload PDFs, paste URLs, ask questions it's like having a research assistant that never sleeps.

But there's one maddening catch: the sidebar becomes a nightmare when you have more than 10 notes.

Imagine:

  • 15 research papers on Spring Framework
  • 8 articles about microservices
  • 12 random bookmarks you saved "for later"
  • All. In. One. Giant. List.

No folders. No organization. Just... chaos.

The Solution: NotebookLM Enhancer

I built a Chrome extension that injects a complete folder management system directly into NotebookLM's sidebar.

Key Features

πŸ—‚οΈ Smart Folder Organization

  • Create folders and subfolders (1 level deep keeping it simple!)
  • Drag & drop notes between folders with smooth animations
  • "Inbox" view for unassigned notes
  • Each notebook project has isolated folders (no cross-contamination!)

πŸ§‘β€πŸŽ¨ Polished UI That Matches NotebookLM

  • Built with Angular + Tailwind CSS
  • Dark/light/system theme toggle
  • Minimalist design that feels native
  • Smooth expand/collapse animations

🌎Internationalization

  • Full i18n support (English/Spanish currently)
  • One-click language switcher
  • All UI text translatable

πŸ’­Intelligent Integrations

  • Click any note β†’ opens native NotebookLM
  • Click 3-dots menu β†’ native menu appears aligned to the right (matching native position)
  • Drag notes from native sidebar β†’ drops into our folders
  • Add new notes button that triggers native NotebookLM

Robust Architecture

  • Chrome Extension MV3 (latest manifest version)
  • Content Scripts + Shadow DOM for style isolation
  • Iframe-based Angular app for the UI
  • PostMessage bridge for iframe ↔ page communication
  • chrome.storage.sync for persistence across devices

Architecture Deep Dive

This isn't a simple content script that adds a few buttons. It's a full micro-frontend architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  NotebookLM Page                                        β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Native Sidebar (hidden but functional)          β”‚   β”‚
β”‚  β”‚  β€’ Still handles clicks & menus                  β”‚   β”‚
β”‚  β”‚  β€’ We extract data from it                       β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β”‚                       ↓                                 β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚
β”‚  β”‚  Our Injected Host (Shadow DOM)                  β”‚   β”‚
β”‚  β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”   β”‚   β”‚
β”‚  β”‚  β”‚  Iframe (Angular App)                     β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Folder tree                            β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Drag & drop (Angular CDK)              β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Theme toggle                           β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ Note add. folder add...                β”‚   β”‚   β”‚
β”‚  β”‚  β”‚  β€’ i18n                                   β”‚   β”‚   β”‚
β”‚  β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚   β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜   β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
Enter fullscreen mode Exit fullscreen mode

Why an iframe inside Shadow DOM?

  • Isolation: NotebookLM uses Angular Material with global styles our iframe keeps our Tailwind styles pristine
  • Security: Content scripts can't easily access iframe internals (and vice versa)
  • Performance: Angular app runs independently without polluting the main page

Communication Flow:

  1. Content script reads native DOM β†’ extracts notebook data
  2. PostMessage to iframe β†’ Angular displays organized folders
  3. User drags note to folder β†’ PostMessage back to content script
  4. Content script updates chrome.storage.sync

Technical Decisions

1. Storage V3 with Notebook Isolation

Instead of one global folder structure, each NotebookLM project gets its own isolated state:

// StorageStateV3
{
  byNotebook: {
    "uuid-abc-123": {
      folders: [...],
      notebookFolderByKey: {...}
    },
    "uuid-def-456": {
      folders: [...],
      notebookFolderByKey: {...}
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

This means your "Work" folder structure doesn't leak into your "Personal" research. Clean separation.

2. Handling MV3 Service Worker Sleep

Chrome MV3 Service Workers sleep after 30 seconds of inactivity. This breaks chrome.runtime calls.

Instead of fighting it with "keep-alive" hacks, we:

  • Detect context invalidation gracefully
  • Silently retry on the next frame
  • Log to our own NLE.log() instead of spamming console.warn

3. Native Drag Bridge

Making the native NotebookLM sidebar items draggable was tricky. We:

  • Hook dragstart on native items
  • Create an invisible overlay above our iframe during drag
  • Calculate drop target using elementFromPoint() with coordinates
  • Result: Native notes can be dropped into our folders seamlessly

4. Auto-Focus Input in Modals

Small UX detail that makes a huge difference:

  • Create folder β†’ input already focused, ready to type
  • Rename folder β†’ text is pre-selected, just type to replace
  • No extra clicks needed

πŸ“Έ Screenshots

Before:
Original Notebook1

Original Notebook2

After:

After Enhancer1

After Enhancer2

Export your notes :

Export your notes

Drag & Drop:

Drang and drop

🎬 Video Walkthrough

Watch the full demo on Google Drive


My Experience with GitHub Copilot CLI

This project was built almost entirely through GitHub Copilot CLI interactions turning natural language into production-ready code.

How I Used Copilot CLI

1. Architecture Decisions

# Asked Copilot: "Best way to inject UI into an existing Angular Material page?"
# Copilot suggested: Shadow DOM + iframe for isolation
# Result: Zero style conflicts with NotebookLM's Material Design
Enter fullscreen mode Exit fullscreen mode

2. Content Script Structure

# Asked: "How to structure 8 content scripts that share state?"
# Copilot proposed: Module pattern with window.__NLE__ namespace
# Result: Clean separation, no global pollution
Enter fullscreen mode Exit fullscreen mode

3. Drag & Drop Implementation

# Asked: "Bridge native HTML5 drag with Angular CDK drop?"
# Copilot designed: Overlay system with coordinate translation
# Result: Seamless drag from native sidebar to our folders
Enter fullscreen mode Exit fullscreen mode

4. Debugging Context Invalidation

# Asked: "Chrome MV3 extension context invalidated errors?"
# Copilot implemented: Graceful detection + silent retry logic
# Result: No console spam, smooth recovery
Enter fullscreen mode Exit fullscreen mode

5. i18n System

# Asked: "Lightweight i18n without ngx-translate bloat?"
# Copilot built: Custom TranslationService with lazy loading
# Result: ~3KB vs ~50KB, full interpolation support
Enter fullscreen mode Exit fullscreen mode

Wins

Speed: What would have taken weeks took days. Complex features like the drag bridge were implemented in hours, not days.

Architecture: Copilot suggested patterns I wouldn't have considered (like the iframe-in-shadow approach) that solved isolation problems elegantly.

Edge Cases: MV3 quirks, Material Design menu positioning, SPA navigation detection Copilot handled these gracefully.

Learning: Every interaction was a learning moment :) . I now understand Chrome Extension architecture, Angular standalone components, and Tailwind customization.


What's Next?

  1. Chrome Web Store Launch - Polish, package, publish
  2. More Languages - French, German, Portuguese (easy with our i18n system)
  3. Search & Filter - Find notes within folders instantly
  4. Keyboard Shortcuts - Power-user features (Ctrl+Shift+N for new folder)

🀝 Open Source

This project will be open-sourced. Want to contribute?

  • PRs welcome
  • Good first issues: translations, themes, documentation

Credits & Thanks

  • Google for NotebookLM an incredible research tool
  • GitHub Copilot CLI for turning ideas into code faster than ever <3
  • Tailwind CSS for making dark mode trivial
  • DEV.to for hosting this challenge and bringing the community together

Built with ❀️, and a lot of help from GitHub Copilot CLI.

Top comments (0)