Guide

Nesting

Composing and nesting styles


Overview

This page explains how to compose and layer ebcprep's configuration to build flexible, reusable setups. By combining .env settings, defaults.toml declarations, and feeder-sheet columns, you can nest shared defaults under per-executive overrides — keeping your configuration DRY without sacrificing the per-meeting control your EBC team needs.


Prerequisites

Before working through the examples on this page, make sure you have:

  • Python ≥ 3.11 installed and on your PATH
  • uv (Astral package manager) installed
  • notebooklm-mcp-cli (nlm) ≥ 0.6.5 installed and authenticated (nlm login --profile <name>)
  • A .env file configured with your service-account path, Sheet ID, and NotebookLM profile name
  • A feeder spreadsheet populated with at least one meeting row
  • (Optional) A defaults.toml file if you want to define always-included collaborators or default sources

See the Install and authenticate and Configure the tool guides if any of these are not yet in place.


Installation

1. Install uv (if not already installed)

curl -Lsf https://astral.sh/uv/install.sh | sh

2. Clone or download ebcprep and install dependencies

git clone https://github.com/your-org/ebcprep.git
cd ebcprep
uv sync

3. Install the nlm companion CLI

uv tool install notebooklm-mcp-cli

Verify the version is ≥ 0.6.5:

nlm --version

4. Authenticate with NotebookLM

nlm login --profile my-ebc-profile

This opens Chrome for interactive sign-in and saves your session locally. ebcprep uses this saved session for all subsequent notebook operations — you do not need to log in again on re-runs.

5. Run the health check

ebcprep doctor

Fix any reported issues before proceeding to configuration.


Configuration

ebcprep's configuration is split across two files and the feeder sheet, each at a different scope:

.env — connection settings (required)

Stored at the project root. Controls how ebcprep reaches Google APIs and NotebookLM.

KeyDescriptionExample value
GOOGLE_SERVICE_ACCOUNT_JSONPath to your GCP service-account key file./keys/sa.json
SHEET_IDThe ID from your feeder spreadsheet's URL1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgVE2upms
NLM_PROFILEThe profile name you used with nlm loginmy-ebc-profile

defaults.toml — shared defaults (optional)

Stored at the project root. Anything defined here applies to every notebook ebcprep creates or updates, letting you avoid repeating the same collaborators and documents in every feeder-sheet row.

# defaults.toml

[collaborators]
always_collaborators = [
  "ebc-ops@example.com"
]

[sources]
default_sources = [
  "https://docs.google.com/document/d/BRIEFING_STANDARDS_DOC_ID/edit"
]
  • always_collaborators — email addresses added as editors to every notebook, regardless of which executive the notebook belongs to. Useful for an EBC operations mailbox or a shared team account.
  • default_sources — Google Doc URLs added as sources to every notebook, regardless of meeting content. Useful for standing documents like a corporate briefing standards guide.

Feeder spreadsheet — per-meeting overrides

Columns in the feeder sheet provide per-row values that augment (not replace) the defaults above:

  • Columns M (ea_email) and N (cos_email) — when present, the Executive Assistant and Chief of Staff are automatically invited as editors for that executive's notebook.

The effective collaborator list for any notebook is: always_collaborators (from defaults.toml) plus any ea_email/cos_email values from the executive's meeting rows.


Usage

Layering defaults with per-executive settings

The most common pattern is to define team-wide defaults in defaults.toml and let per-executive overrides come from the feeder sheet. You never need to repeat the EBC ops mailbox or the briefing standards doc on every row.

Typical workflow:

  1. Add your always-included collaborators and default sources to defaults.toml once.
  2. Fill out the feeder sheet with executive-specific columns (name, company, prep doc URL, meeting date/time, and optionally EA/COS emails).
  3. Preview what ebcprep will do:
ebcprep sync --dry-run
  1. Run the actual sync:
ebcprep sync

ebcprep merges the defaults.toml values with each row's data automatically — you do not need to pass any extra flags.

Re-running safely

Because ebcprep is idempotent, you can run ebcprep sync again after adding new rows to the feeder sheet. Rows already processed are detected by their content hash and skipped; only new or changed meetings trigger API calls.

ebcprep sync

Checking what has already been processed

ebcprep status

This reads the local state database (data/ebcprep.db) and shows which executives have notebooks, which sources have been added, and which invites have been sent.


Examples

Example 1 — Minimal defaults.toml with one always-collaborator

Add the EBC operations mailbox to every notebook without touching the feeder sheet:

# defaults.toml
[collaborators]
always_collaborators = ["ebc-ops@example.com"]

Run a dry-run to confirm the collaborator appears on every notebook:

ebcprep sync --dry-run

Expected output (abbreviated):

[DRY RUN] Executive: Jane Smith
  Notebook: (would create)
  Sources to add: 1
  Invites to send: ebc-ops@example.com
[DRY RUN] Executive: Carlos Rivera
  Notebook: (would create)
  Sources to add: 2
  Invites to send: ebc-ops@example.com

Example 2 — Adding a default source to every notebook

Include a standing corporate briefing guide in every executive notebook:

# defaults.toml
[collaborators]
always_collaborators = ["ebc-ops@example.com"]

[sources]
default_sources = [
  "https://docs.google.com/document/d/1aBcDeFgHiJkLmNoPqRsTuVwXyZ/edit"
]
ebcprep sync

Expected output (abbreviated):

[sync] Executive: Jane Smith — notebook found, adding 1 meeting source + 1 default source
[sync] Executive: Carlos Rivera — notebook created, adding 2 meeting sources + 1 default source
[sync] Done. 2 notebooks updated, 0 skipped.

Example 3 — Per-executive EA and COS from the feeder sheet

With ea_email (column M) and cos_email (column N) filled in for a row, those people are automatically invited in addition to any always_collaborators:

# Feeder sheet row (columns shown as key: value)
exec_name:  Jane Smith
company:    Acme Corp
prep_doc:   https://docs.google.com/document/d/PREP_DOC_ID/edit
date:       2025-09-15
start_time: 10:00
end_time:   11:00
ea_email:   jane-ea@example.com
cos_email:  jane-cos@example.com
ebcprep sync --dry-run

Expected output:

[DRY RUN] Executive: Jane Smith
  Sources to add: 1
  Invites to send: ebc-ops@example.com, jane-ea@example.com, jane-cos@example.com

The ebc-ops address comes from defaults.toml; the EA and COS addresses come from the feeder sheet. Both sets are merged automatically.


Troubleshooting

Always-collaborator not appearing on notebooks

Symptom: After running ebcprep sync, the email listed in defaults.toml under always_collaborators is not invited to one or more notebooks.

Likely cause: The defaults.toml file is not in the project root, or the key name is misspelled (e.g., always_collaborator instead of always_collaborators).

Fix: Confirm the file exists at ./defaults.toml and that the array key is exactly always_collaborators. Run ebcprep doctor to surface configuration errors, then re-run ebcprep sync.


Default source added to some notebooks but not others

Symptom: The document listed in default_sources appears in notebooks created during a fresh run but not in notebooks that already existed before defaults.toml was added.

Likely cause: ebcprep's idempotency system already marked those notebooks as fully processed. The state database records work already done and skips it on re-runs.

Fix: This is expected for notebooks whose rows haven't changed. To force a re-sync for a specific executive, delete the corresponding rows from data/ebcprep.db, or — to re-sync everything — delete the state database file entirely and re-run ebcprep sync. Deleting the database causes ebcprep to treat every row as new.


EA / COS invite not sent despite columns being populated

Symptom: Columns M and N are filled in the feeder sheet, but the EA or COS did not receive a notebook invite.

Likely cause: The row was already processed before columns M/N were added. Because the content hash is computed from the executive name and prep-doc URL, adding email columns alone does not change the hash, so the row is skipped.

Fix: To force re-processing of that row, remove it from the state database or temporarily change the prep-doc URL, run ebcprep sync, then revert the URL. Alternatively, delete data/ebcprep.db to trigger a full re-sync.


ebcprep doctor reports missing NLM profile

Symptom: ebcprep doctor prints an error such as NLM profile 'my-ebc-profile' not found.

Likely cause: The profile name in .env does not match the name used when running nlm login --profile <name>, or the login session has expired.

Fix: Re-run nlm login --profile <name> using the exact profile name set in NLM_PROFILE inside your .env file, then re-run ebcprep doctor to confirm the session is valid.