Skip to content

Repository files navigation

loom-daddy

Turns your Loom recordings into reviewed action plans in Notion, with an optional markdown copy (plan plus raw transcript) in Google Drive. Installed as a Claude Code plugin it runs on your Claude subscription: no LLM API keys, and no .env for the common case.

Loom has no public API; this uses an authenticated-session approach scoped to your personal account. Treat the stored session as a credential, and read "Known limits" before installing.

Install

/plugin marketplace add fontezbrooks/loomDaddy
/plugin install loom-daddy@loomDaddy

First-time setup

One required step: sign in to Loom.

/loom-daddy:loom-auth

This opens a real browser. Complete Google SSO by hand (Google blocks automated sign-in); the script detects the signed-in session and saves it automatically, no terminal input needed. Re-run it whenever the session expires (override the wait with LOGIN_TIMEOUT_MS).

Optionally confirm everything is wired up:

/loom-daddy:setup     # doctor: session + Notion MCP + (optional) Drive

Nothing else is needed for the common case:

  • Analysis runs on your Claude subscription (no LLM API key).
  • Notion publishing uses your connected Notion MCP (no Notion token). You name the target database once on your first publish and it is remembered.
  • State (session, seen-recordings ledger, cached Notion destination) lives in ~/.loom-daddy (override with LOOM_DADDY_DATA_DIR) and survives plugin upgrades.

Use

/loom-daddy:list                                   # recent recordings
/loom-daddy:analyze <id>                           # transcript -> action plan
/loom-daddy:render <id>                            # action plan -> markdown
/loom-daddy:publish <id> [--to notion|drive|both]  # push the plan out
/loom-daddy:process                                # full pipeline over all new recordings
/loom-daddy:status                                 # session and pipeline state

Natural language works too ("analyze my standup loom and put it in Notion") via the model-invocable loom skill.

Each plan contains a summary, decisions, action items with inferred owners, priorities and timeframes, timestamped source links back to the recording, and open questions.

Google Drive copy (optional)

Drive upload (a transcript plus action-plan markdown copy per recording) is optional: when DRIVE_FOLDER_ID / GOOGLE_APPLICATION_CREDENTIALS are unset, the Drive step skips itself with a notice and Notion publishing still works.

To enable it with your own Google account (verified flow, OAuth via the Google Workspace CLI):

  1. Install and configure the gcloud CLI for basic auth: https://cloud.google.com/sdk/docs/install
  2. Install and configure the Google Workspace CLI (gws), making sure to select Google Drive when it asks which services to grant: https://github.com/googleworkspace/cli#interactive-local-desktop
  3. Export the credential:
    gws auth export --unmasked > credentials.json
    
    This writes an authorized_user OAuth credential (client id/secret + refresh token). It is a real credential: keep it out of git and out of shared folders.
  4. Set GOOGLE_APPLICATION_CREDENTIALS to that file's absolute path.
  5. Open the target Drive folder in a browser and copy the id from the URL (https://drive.google.com/drive/folders/<DRIVE_FOLDER_ID>); set DRIVE_FOLDER_ID.

As a plugin, set both variables in a .env file in the installed plugin directory (/loom-daddy:setup tells you where and verifies the result: it should report [OK] Drive configured (optional)). For the standalone daemon, set them in the repo .env. A service-account key JSON with Drive scope also works for GOOGLE_APPLICATION_CREDENTIALS if you prefer machine credentials over a personal OAuth grant.

Background scheduler (optional)

/loom-daddy:schedule install [--interval N]   # default: every 45 minutes
/loom-daddy:schedule status                   # installed? loaded? auth reachable? log path
/loom-daddy:schedule remove

Installs a per-user macOS LaunchAgent that runs /loom-daddy:process --commit on a schedule, on your Claude subscription. Preview the generated plist with install --dry-run. Stay logged in for the first run so the subscription credential is reachable (keychain access only exists in the logged-in session).

It is local-only by design: the authenticated Loom session lives on your machine, so a hosted/remote agent cannot drive it.

Troubleshooting

  • First diagnostic for anything: /loom-daddy:setup. It checks the session, data dir, Notion MCP, and optional Drive config, and says what to fix.
  • Loom session expired (list/analyze/process start failing auth): /loom-daddy:loom-auth again. Sessions need one periodic manual refresh; there is no way around the interactive SSO.
  • Notion publish has no destination: you name the target database on your first /loom-daddy:publish (for example "publish to my Meeting Notes database"); it is then remembered in ~/.loom-daddy.
  • After updating the plugin: updates install into a new versioned plugin directory, and two things do not follow automatically. (1) The scheduler's LaunchAgent has the old directory baked in, so re-run /loom-daddy:schedule install after an update. (2) A plugin-directory .env (Drive config) does not carry over; re-create it, then re-run /loom-daddy:setup to verify. Everything in ~/.loom-daddy (session, ledger, Notion destination) does survive updates.
  • Doc or behavior changes not showing up: installed plugins are pinned to the version they were installed at; update the plugin from /plugin to pull a newer release.

Standalone daemon (advanced)

The pipeline also runs outside Claude Code as a plain Node daemon: API-key based, with a pluggable LLM provider, publishing to Notion via the API instead of MCP. Use this for a headless runner or if you do not use Claude Code.

Setup

npm install
npx playwright install chromium   # only needed on the runner host

Environment (required): NOTION_TOKEN, NOTION_PARENT_DATABASE_ID, DRIVE_FOLDER_ID, GOOGLE_APPLICATION_CREDENTIALS (see "Google Drive copy" above), plus the selected LLM provider's credentials (below). Optional: LOOM_LOOKBACK_DAYS, POLL_OVERLAP_MINUTES, POLL_CRON, STORAGE_STATE_PATH, STATE_PATH, LOOM_BASE_URL.

LLM provider (pluggable)

LLM_PROVIDER selects the model adapter (default anthropic). Only the selected provider's credentials are required, so you can keep several configured and switch by flipping one var.

  • anthropic (default): ANTHROPIC_API_KEY, optional ANTHROPIC_MODEL.
  • gemini: AI Studio GEMINI_API_KEY, or Vertex via GEMINI_PROJECT_NAME (+ optional GEMINI_LOCATION, default global). Optional GEMINI_MODEL (default gemini-3-flash-preview). Requires the optional dep: npm i @google/genai.
  • ollama (local): OLLAMA_MODEL, optional OLLAMA_HOST (default http://localhost:11434). No API key; runs against a local Ollama daemon.

Per-run override on analyze/run-once: --provider <name> and --model <name>. Example: tsx scripts/analyze.ts <id> --provider gemini --model gemini-3-pro-preview.

Login and run

npm run login     # same interactive Google SSO as the plugin login
npm start         # runs one cycle immediately, then on POLL_CRON

Stage helper scripts (debugging / iteration)

Each workflow stage runs in isolation via tsx scripts/<stage>.ts, chaining through a gitignored artifacts/ dir (<id>.transcript.json, <id>.meta.json, <id>.plan.json, <id>.action-plan.md). Most scripts accept a bare video id (resolved against artifacts/) or an explicit file path. Stages that write to Drive/Notion are dry-run by default; pass --commit to perform real writes.

tsx scripts/list.ts [--days N] [--limit N] [--json]   # find a recording id (session)
tsx scripts/session-check.ts                          # is the stored session still valid?
tsx scripts/resolve-url.ts <id>                        # print the signed transcript URL (parser debug)
tsx scripts/download.ts <id> [--days N]               # Loom -> <id>.transcript.json + <id>.meta.json
tsx scripts/analyze.ts <id|file> [--meta f] [--provider p] [--model m]  # transcript -> <id>.plan.json
tsx scripts/render.ts <id|file>                        # plan -> <id>.action-plan.md (no network)
tsx scripts/save.ts <id|file> [--commit]              # transcript -> Drive
tsx scripts/publish.ts <id|file> [--transcript f] [--commit]  # plan -> Notion + Drive
tsx scripts/record-publish.ts <id> --url <pageUrl>    # record a Notion publish done via MCP
tsx scripts/mark.ts <id> [--force]                    # ledger the id (needs a Notion receipt)
tsx scripts/run-once.ts <id> [--days N] [--provider p] [--model m] [--commit]  # full chain for one id
tsx scripts/clean.ts                                  # wipe the artifacts dir

analyze and render need no Loom session, so they run offline against fixtures (e.g. the HAR-derived transcript) for prompt and formatting iteration. ARTIFACTS_DIR overrides the artifacts location.

How it works

  1. Two GraphQL queries list recordings in a poll window: recentUserVideos (your own recordings) and GetCalendarMeetings (recorded meetings on your synced calendar, regardless of who recorded them; recorder attribution is published to Notion).
  2. Fully-processed + unseen recordings are selected (idempotency ledger); the two sources are merged by video id. If one source errors the other still processes.
  3. Each recording's share page yields a short-lived signed CDN transcript URL.
  4. The transcript JSON (phrases: [{ts, value, speakerName}]) is fetched immediately.
  5. Claude returns a schema-validated action plan (summary, decisions, action items with inferred owners/priorities/timeframes, timestamp source links, open questions).
  6. The plan is published to Notion and written, with the raw transcript, to Google Drive.

The trigger is a poll (no Loom webhook exists), so it is near-real-time.

Develop

npm test          # vitest, core logic against real fixtures from the HAR
npm run typecheck # tsc --noEmit

Architecture keeps all network and SDK access behind injectable interfaces (HttpClient, StructuredModel, NotionApi, DriveApi), so the core (loom/, transcript/, analyze/, publish/, state/, runner.ts) is unit-tested without network. Heavy SDKs (Playwright, Anthropic, Notion, googleapis) are loaded via dynamic import in session/ and integrations/ and are optional dependencies.

Known limits

  • ToS-gray: automated credentialed access to Loom. Scoped to a personal account, internal/low-risk content; treat the stored session as a credential.
  • Fragile points: loom/sharePage.ts and loom/queries.ts ride undocumented endpoints.
  • One periodic manual session refresh (/loom-daddy:loom-auth or npm run login) when the session expires.
  • Meetings recorded by a teammate whose sharing settings restrict access warn-and-retry each cycle until that recorder grants workspace viewing access.
  • When upgrading to the meetings-aware build (0.3.0) with forward-only intent, write the current ISO timestamp into state/watermark.json first; an absent watermark backfills lookbackDays of teammates' meetings.
  • Design, research, and requirements notes are maintained separately (internal).

About

Meeting-intelligence agent for Loom: reverse-engineered transcript endpoints, schema-validated LLM analysis, action plans to Notion/Drive. Packaged as a Claude Code plugin (87 tests) with a private team marketplace.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages