Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .claude-plugin/marketplace.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
{
"name": "take-notes",
"description": "Turn a YouTube video, web article, arXiv paper, or GitHub repo into didactic study notes as a self-contained HTML page, kept in a browsable local archive.",
"version": "1.0.1",
"version": "1.1.0",
"author": {
"name": "Daniel Verdu",
"url": "https://github.com/davertor"
Expand Down
2 changes: 1 addition & 1 deletion .claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "take-notes",
"version": "1.0.1",
"version": "1.1.0",
"description": "Turn a YouTube video, web article, arXiv paper, or GitHub repo into didactic study notes — executive summary, the one takeaway, key points, and a timestamped or sectioned outline — as a self-contained HTML page you keep, browse, and export.",
"author": {
"name": "Daniel Verdu",
Expand Down
2 changes: 1 addition & 1 deletion .codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "take-notes",
"version": "1.0.1",
"version": "1.1.0",
"description": "Turn a YouTube video, web article, arXiv paper, or GitHub repo into didactic study notes — executive summary, the one takeaway, key points, and a timestamped or sectioned outline — as a self-contained HTML page you keep, browse, and export.",
"author": {
"name": "Daniel Verdu",
Expand Down
2 changes: 1 addition & 1 deletion .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ body:
description: Helps localise the failure fast.
value: |
```
for s in render notes gallery export transcript tags; do
for s in render notes gallery export transcript tags retag slides; do
uv run skills/take-notes/scripts/$s.py --selftest
done
```
Expand Down
2 changes: 1 addition & 1 deletion .github/PULL_REQUEST_TEMPLATE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

## Checks

- [ ] `for s in render notes gallery export transcript tags; do uv run skills/take-notes/scripts/$s.py --selftest; done` passes
- [ ] `for s in render notes gallery export transcript tags retag slides; do uv run skills/take-notes/scripts/$s.py --selftest; done` passes
- [ ] No new third-party dependency (see CONTRIBUTING.md)
- [ ] English throughout — code, comments, commit messages

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
# the whole test suite. See CONTRIBUTING.md.
- name: Run script self-checks
run: |
for s in render notes gallery export transcript tags retag; do
for s in render notes gallery export transcript tags retag slides; do
echo "--- $s"
uv run skills/take-notes/scripts/$s.py --selftest
done
Expand Down
32 changes: 32 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,38 @@ All notable changes to this project are documented here, in the
release adds a section here, bumps `skills/take-notes/SKILL.md`'s `version`,
and tags — see [CONTRIBUTING.md](CONTRIBUTING.md).

## [1.1.0]

### Added

- **Google Slides as a source.** `/take-notes <presentation URL>` now reads a
deck: per-slide text, speaker notes, and a rendered image for every slide.
New `references/slides.md` guide and `scripts/slides.py`, stdlib only — Google
exports any link-visible deck as `.pptx` without an API key, and a pptx is a
zip of XML.
- **A deck's diagrams reach the note.** Each slide's Google page id, read out of
the shape names on its notes page, addresses a 960×540 render at
`export/png?pageid=<id>`. Rendering the whole slide is what catches a diagram
drawn from native shapes — boxes and arrows that exist in no image file, and
that extracting embedded media would miss entirely. `slides.py` reports per
slide how many images, shapes and connectors it carries, which is the
shortlist of what is worth a figure.
- `slides.py` says in its header whether speaker notes exist (`on 12 of 16
slides` / `none written on any slide`), so a deck nobody annotated cannot be
mistaken for notes that failed to parse.

### Changed

- SKILL.md's *Article figures* rule is now *Source figures*, covering articles,
papers and decks alike, with the same cap of 3 and the same
confirm-it-is-really-an-image check.

### Fixed

- The figure check in `references/web.md` now passes `-L`. Without it a host
that answers a redirect (a CDN, or Google's own image export) reads as a
failure, and a perfectly good figure gets dropped.

## [1.0.1]

### Fixed
Expand Down
7 changes: 4 additions & 3 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ There is no test suite. Each script with non-trivial logic carries its own
asserts behind `--selftest`, and all of them must pass before a PR:

```sh
for s in render notes gallery export transcript tags retag; do
for s in render notes gallery export transcript tags retag slides; do
uv run skills/take-notes/scripts/$s.py --selftest
done
```
Expand Down Expand Up @@ -62,8 +62,9 @@ adding one guide and one routing row — never a second copy of the writing
rules, which would immediately drift from the first.

The routing table in `SKILL.md` Step 1 is matched **top to bottom, first match
wins**. `arxiv.org` and `github.com` are `http(s)` pages, so they must stay
above the catch-all `web.md` row or they will never be reached.
wins**. `arxiv.org`, `docs.google.com/presentation` and `github.com` are
`http(s)` pages, so they must stay above the catch-all `web.md` row or they will
never be reached.

### 3. The note templates are a machine-readable contract

Expand Down
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
</p>

<p align="center">
<img src="https://img.shields.io/badge/version-1.0.0-ab2f19?style=flat-square&labelColor=191511" alt="Version 1.0.0">
<img src="https://img.shields.io/badge/version-1.1.0-ab2f19?style=flat-square&labelColor=191511" alt="Version 1.1.0">
<a href="LICENSE"><img src="https://img.shields.io/badge/license-MIT-57503f?style=flat-square&labelColor=191511" alt="MIT license"></a>
<img src="https://img.shields.io/badge/agents-any%20Agent%20Skills%20host-57503f?style=flat-square&labelColor=191511" alt="Compatible with any Agent Skills host">
<img src="https://img.shields.io/badge/output-html%20%C2%B7%20md%20%C2%B7%20anki-57503f?style=flat-square&labelColor=191511" alt="Output: HTML, Markdown, Anki">
</p>

**Notes you can actually learn from — not a transcript dump, not a one-paragraph summary.**

Point it at a video, an article, a paper, or a repo. You get a self-contained
Point it at a video, an article, a paper, a slide deck, or a repo. You get a self-contained
HTML page — executive summary, the one takeaway, key points, and a timestamped
or sectioned outline — written to `~/take-notes/html_reports/` and opened in
your browser. They pile up into a browsable archive you own, on your disk, in
Expand Down Expand Up @@ -79,6 +79,7 @@ Point it at a URL. That is the whole thing:
/take-notes https://www.youtube.com/watch?v=NiKtZgImBdY
/take-notes https://simonwillison.net/2025/Jan/11/phi-4-bug-fixes/
/take-notes https://arxiv.org/abs/2407.09141
/take-notes https://docs.google.com/presentation/d/1hcGZ4U9TjZZzcGNbH2K6wYD45qwZTyo_gosCQsnHlnc/edit
/take-notes https://github.com/ggml-org/llama.cpp
```

Expand All @@ -97,6 +98,7 @@ conversation, in any tool it's installed in.
| **Local media** | video or audio already on disk |
| **Web articles** | blog posts, docs pages, news articles |
| **arXiv papers** | full text via arXiv's HTML rendering, not just the abstract |
| **Google Slides** | slide text plus the speaker notes, and the deck's diagrams as figures |
| **GitHub repos** | an orientation note: what it does, how it's laid out, what to read first |

### Focus
Expand Down Expand Up @@ -278,7 +280,8 @@ folder instead of your user directories. Update with `npx skills update take-not
| **Whisper API key** | optional, only for videos without captions — Groq or OpenAI, read from `~/.config/watch/.env` |


Web articles need none of the above — that path uses the agent's fetch tool.
Web articles need none of the above — that path uses the agent's fetch tool —
and Google Slides needs only `uv`: the deck reader is standard library, no API key.

Both install paths land on the same `/take-notes` — neither namespaces nor
renames it.
Expand Down
28 changes: 16 additions & 12 deletions skills/take-notes/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ license: MIT
compatibility: Requires uv. Video sources also need yt-dlp and ffmpeg, plus network access; an optional Groq or OpenAI key enables Whisper for videos without captions.
metadata:
author: davertor
version: "1.0.1"
version: "1.1.0"
# Claude Code extensions below — not in the agentskills.io spec, and read at the
# top level rather than under `metadata`, which is where Claude Code looks.
# `allowed-tools` stays comma-separated: the spec asks for spaces but marks the
Expand Down Expand Up @@ -104,13 +104,14 @@ regenerated, so it costs the listing and the model's choices, nothing more.
Pick **one** reference by looking at the source, Read it, and follow it. Only the
acquisition differs; everything after Step 2 is identical for every source.

Match **top to bottom and stop at the first row that fits** — arXiv and GitHub
links are `http(s)` pages too, so the catch-all row would swallow them.
Match **top to bottom and stop at the first row that fits** — arXiv, Slides and
GitHub links are `http(s)` pages too, so the catch-all row would swallow them.

| Source | Read |
|---|---|
| YouTube URL, any other video URL yt-dlp supports, or a local media file | `references/youtube.md` |
| `arxiv.org` (or an `ar5iv` / arXiv DOI link) — a paper | `references/arxiv.md` |
| `docs.google.com/presentation/...` — a slide deck | `references/slides.md` |
| `github.com/<owner>/<repo>` — a repository root, not a file, PR, or issue | `references/github.md` |
| Any other `http(s)` page — blog post, docs page, news article | `references/web.md` |

Expand All @@ -123,7 +124,7 @@ Each guide hands back the same thing, and nothing more:
date for a paper, latest release for a repo
- **canonical URL** (plus the YouTube video ID when there is one)
- **body** — the timestamped transcript, the article text, the paper full text,
or the README plus the repo's structure
the deck's slides and speaker notes, or the README plus the repo's structure

Video sources also hand back, when yt-dlp reports them: **channel URL**,
**published** date, **views**, a **thumbnail** URL, and the **caption language**.
Expand Down Expand Up @@ -302,14 +303,17 @@ Optional — include only when the source actually earns it, never as an empty h
- `<h2>Going deeper</h2>` — what the source leaves open: unanswered questions,
claims made without evidence, and the concrete next thing to read or try.

**Article figures** — `references/web.md` returns any diagrams, charts, or
screenshots the source page had. Include one only when it is load-bearing —
the diagram *is* the explanation, the chart *is* the evidence — never a
decorative photo, a header banner, or an author headshot. Cap at 3, the same
"more than that is a dump" discipline as Key Points. Not a section of its
own: place `<figure><img src="<url>" alt="<alt text>"><figcaption>caption</figcaption></figure>`
**Source figures** — `web.md` and `arxiv.md` return the diagrams, charts, and
screenshots the page carried; `slides.md` returns an image URL for every slide.
Include one only when it is load-bearing — the diagram *is* the explanation, the
chart *is* the evidence — never a decorative photo, a header banner, an author
headshot, or (for a deck) a slide that is just bullets you already wrote out.
Cap at 3, the same "more than that is a dump" discipline as Key Points. Not a
section of its own: place
`<figure><img src="<url>" alt="<alt text>"><figcaption>caption</figcaption></figure>`
inline, in whichever section it supports — most often *How it works*, *Key
points*, or *Concepts*.
points*, or *Concepts*. Each guide says how to confirm the URL really serves an
image before you embed it; a broken-image icon teaches nothing.

## Rules

Expand All @@ -329,7 +333,7 @@ points*, or *Concepts*.
in Step 2; the structure doesn't change. Pass the matching `--lang` (`en` or `es`)
to the renderer.
- **Keep the HTML plain:** headings, paragraphs, lists, `<strong>`, `<em>`, links,
`<pre><code>`, `<blockquote>`, simple tables, and (articles only)
`<pre><code>`, `<blockquote>`, simple tables, and (every source but video)
`<figure><img><figcaption>` for a source figure. No inline `style` attributes, no
`<script>`, no classes — the stylesheet already handles presentation, and a note
that fights it will look wrong in dark mode.
Expand Down
113 changes: 113 additions & 0 deletions skills/take-notes/references/slides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Acquisition — Google Slides presentation

Acquisition only. Return the fields listed in SKILL.md Step 1 and go back there
to write the notes.

`SKILL_DIR` is already resolved in SKILL.md — reuse it.

## Read the deck

```bash
uv run "${SKILL_DIR}/scripts/slides.py" "<presentation URL>"
```

Prints the deck title, the slide count, and one `### Slide N` block per slide
carrying its text, its **speaker notes**, its **page id**, and a count of what
is drawn on it. No API key and no dependency: Google exports any link-visible
deck as `.pptx`, and a pptx is a zip of XML.

## Read the speaker notes — they are half the source

A slide is a prompt for a person who is about to talk over it. The bullets are
what the audience *sees*; the notes are what the presenter was going to *say* —
the mechanism behind the diagram, the caveat behind the number, the reason this
slide follows the last one. Notes taken from the bullets alone reproduce a deck's
shorthand, which is the exact failure SKILL.md's "didactic means explaining, not
compressing" rule is about.

So treat the notes as body text, equal in standing to the slide's own words, and
prefer them wherever the two disagree in depth. In practice they are where most
of *How it works*, *Concepts*, and *Going deeper* come from — a bullet says
"clean the traces", the note says why deterministic redaction runs before the
LLM review.

The header line says how many slides carry them:

- `on 12 of 16 slides` — read every one before writing anything.
- `none written on any slide` — a fact about the deck, not a parsing failure;
the script checked. Say so in *Going deeper* when the slides are thin enough
that the missing narration is why the notes are shorter than the topic
deserves.

## The figures are the point of this source

A deck's diagrams are frequently the entire argument, and most of them exist in
no image file: a pipeline drawn as boxes and arrows is native Slides shapes, so
extracting embedded media would return the screenshots and miss the diagrams.
Rendering the whole slide catches both.

Every slide has a stable image URL, and the script prints the page id for each:

```
https://docs.google.com/presentation/d/<DECK_ID>/export/png?pageid=<PAGE_ID>
```

960×540 PNG, no auth, straight into `<img src>`.

The per-slide counts are the shortlist. `connectors` is the strongest signal —
boxes alone are a layout, boxes joined by arrows are an explanation. A high
`shapes` count is a built-up diagram or a table; `images` is a pasted
screenshot or chart. `text only` is a bullet slide, and never a figure.

Verify before embedding, the same check `web.md` uses:

```bash
curl -sIL -o /dev/null -w "%{http_code} %{content_type}" "<png URL>"
```

`-L` is not optional here: the export answers `307 application/binary` and
redirects to the rendered image, so without it every figure looks like a failure.

Anything but `200 image/png` means the deck is not link-readable — drop the
figure rather than shipping a broken image, and fold the caption into the prose.

Two things to be honest about in the note when it matters: the URL renders the
deck's **current** slide, so a figure drifts if the deck is later edited, and it
breaks entirely if the deck's sharing is tightened.

Cap and placement follow SKILL.md's **Source figures** rule — at most 3, inline
in the section each one supports, never a gallery.

## Map the output to the Step 1 fields

| Step 1 field | From |
|---|---|
| title | `**Title:**` — the deck's own name |
| byline | the presenter or team named on the title slide; the script cannot report one, so read it off slide 1, and fall back to `Google Slides` when the deck names nobody |
| span | `**Slides:**`, written out in the note's own language — `16 slides` or `16 diapositivas` |
| canonical URL | `**Deck URL:**` — the bare `/edit` form, without the `#slide=` fragment the user's link carried |
| body | the `## Slides` blocks, text and speaker notes together |

A deck has no video ID, so Step 5 renders the article layout. Its `Section
outline` is the deck's own arc: group the slides into the 6–15 moves the talk
actually makes, and link each to its slide with the deep link the script printed
(`.../edit#slide=id.<PAGE_ID>`). One line per slide is a table of contents, not
an outline.

A **focus** narrows which slides matter, not which are fetched — the whole deck
arrives in one download either way.

## Failure

The script exits non-zero and says which of these it hit:

- **not link-readable**: the export answers with a sign-in page. Say so and stop.
The fix is the user's: set sharing to *Anyone with the link → Viewer*, or paste
the content. Do not write notes from the title.
- **not a Slides URL**: a Docs or Sheets link is a different product, and a
`/presentation/` link that is really a published `/pub` page is a web page —
use `references/web.md`.

A deck that is mostly screenshots with three words per slide has no body to take
notes from. Say that rather than padding one out; the speaker notes are the last
place to check before giving up.
3 changes: 2 additions & 1 deletion skills/take-notes/references/web.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ image URLs when asked, in document order, with captions attached. It returns
none of that unasked, so don't drop this line.

**Before embedding one as a `<figure>`, confirm it actually serves an image:**
`curl -sI -o /dev/null -w "%{http_code} %{content_type}"` on the URL. A page
`curl -sIL -o /dev/null -w "%{http_code} %{content_type}"` on the URL — with
`-L`, since a CDN that answers a redirect is not a failure. A page
behind bot protection (Cloudflare and similar) returns an HTML challenge page
instead of image bytes for any out-of-browser request — and critically, no
header fixes this, because it also blocks the `<img>` tag in the finished
Expand Down
Loading
Loading