Skip to main content

My Book Summaries in Roam Using Tiago's Progressive Summarization

  • There was an error in the Roam42 Smart Block. This is now corrected. 
  • The SmartBlock is now even smarter. 
    • When you run it, you are prompted to specify the highlight separator. If there are multiple highlights within a paragraph you can specify how it should appear in the stripped output. 
    • You are also prompted to remove **bolding** of text. 
    • The SmartBlock should now be run as a child node of a block that contains the title of the page with the literature highlights.
  • A Roam.JSON is included to make it easier to install the SmartBlock.
  • The "how to" video demonstrating the installation and the execution of the solution is also updated.

Today I will share my personal approach to taking notes on books using Roam. If you are into sketchnoting or if you are using Obsidian, I have a new post on the subject of book summaries: Sketchnoting a Book in Obsidian.

Thank you, Tiago for all your valuable insights on the effective summarization of books using progressive summarization. This post is based on what I've learned from Progressive Summarization: A Practical Technique for Designing Discoverable Notes and Tiago's video series on the same topic: 

  1. How to Decide What to Highlight in eBooks
  2. How to Progressively Summarize a Digital Note
  3. How to Create and Outline with Digital Notes
  4. How to Write a Book Summary

My practice has evolved significantly over the past years. Since about 2002, until May this year, I was a devoted TheBrain addict. TheBrain lends itself to a slightly different type of note-taking style compared to more document-centric systems. My notes on books, online courses, YouTube, etc. in TheBrain are a mix of mind maps and brief text notes, resulting in a highly visual representation of the key thoughts and learnings from the content, I was consuming. 

Since moving to Roam in May and having read Sönke Ahrens's book How to Take Smart Notes, and Tiago's articles on progressive summarization, I have been experimenting with taking more text-heavy notes and creating "proper" book summaries. My current approach is by no means perfect and I am sure that if I write a similar article a year from today, it will have changed considerably. I hope nonetheless that you will be able to take a couple of ideas from my practice and integrate it into your own.

Progressive Summarization

Progressive summarization balances compression with maintaining context. The basic idea is to create a document that is short, searchable, and if I pick it up a couple of years from today, it will hold enough context to remind me of the key points I've learned from reading that book. It is the process of taking a full textbook and creating a mini-summary or remix in such a way, that each step of the compression process is simple to execute and can be accomplished in a relatively short amount of time, spread across time, in the course of other work, and only doing as much or as little as the information deserves. 

Tiago defines 5 layers of summarization, each layer simple to implement, and requiring limited effort. By building the layers one on top of the other the end result is a powerful compression of the text. The beauty of the approach is that it maintains context throughout the process allowing for later drill down into my literature notes or even the book if required.

Layer 0

In Roam I create a page for the book under the [[Book]] namespace and create separate pages for the [[Literature Notes]], [[Reflections]] and [[Summary]] each in their own namespaces. I use [[page references]] for the namespaces to improve querying and filtering my notes in Roam.

Layer 1

UPDATE: Check out my new post on importing ePub books directly into Roam.

I read on a Kindle. My layer 1 notes are text highlights and occasional personal notes next to the highlights. I found Tiago's best practice advice to highlight every chapter title very helpful as this way the resulting kindle highlights maintains the original structure of the book. This provides excellent context when processing the kindle highlights in Roam later. I am very liberal in deciding what I highlight. I typically end up with roughly 5-10% of the book highlighted.

Once finished with the book I use a primitive Python script on to convert the kindle highlights file to an outline that I can import to Roam.   

import re
from google.colab import drive
root = '/content/gdrive/My Drive/'
clippings = 'Kindlehighlights.txt'
clippings_file = open(root+clippings,'r')
kindle_notes = clippings_file.readlines()
print('%d lines read' % len(kindle_notes))
i = 0
page = 0
for line in kindle_notes:
    if i % 5 == 1:
        p2 = re.findall('\d+',line)[0]
        if page != p2:
            page = p2
            print('loc %s' % page)
    if i % 5 == 3:      
        print('\t%s' % re.sub('[\n]+','',line))
    i += 1

Layer 2

Once I've imported my Layer 1 notes into Roam, I read through the notes and use CTRL+Alt 1,2,3 to mark chapter headings. If there are parts, sections, chapters in the book I use headings and indents to structure the text. During this first readthrough I also ^^highlight^^ (CTRL+H) parts of my notes that I find more important. I don't spend too much time deciding what to highlight, I just follow my heart. I typically end up with half or one third of the text highlighted. This typically takes 30 minutes on a 250 page book.

Layer 3

During my second pass through the literature notes I focus my attention on the highlighted text and mark with bold the key words or fragments that I find particularly important. This is second round of review takes about 20 minutes. 

Note: The reason for first highlighting and then marking text bold is due to the way Roam interprets markdown. **bold ^^bold & highlight^^ bold** does not work in Roam unfortunately. ^^highlight **highlight & bold** highlight^^ on the other hand works nicely. I make this note just because Tiago recommends just the opposite, first bold, then highlight. In the end it does not really matter, I am just sharing as an interesting side point.

Layer 4

I write my book summary by reading my highlights in the sidebar and authoring the summary on the [[Summary]]/ page. Thanks to Roam42 SmartBlocks, since today I have a script that I can use to pre-populate the summary page with only my highlights from my literature notes. Once I run the script I go through that text making my edits to finalize the book summary.

My SmartBlock reads the clipboard for the title of the page with my literature notes. My process is the following:

  1. I open the literature notes in the sidebar
  2. I open the [[Summary]]/ page in the main window
  3. I create a page link to the page with my literature highlights on the Summary page (e.g. [[[[Literature Notes]]/The Checklist Manifesto]])
  4. I create a nested block under this page link and execute the Smart Block by typing "jjSummary"
  5. I am prompted to specify the separator to use between highlights, and also to confirm if I want to remove **bold** highlights as well.
  6. Voila, I have all my highlights in my summary including a * reference back to my literature notes, ready to be further processed.

This is how you can install and use Roam42 and my SmartBlock for Progressive Summarization:

Roam #42Smartblock
Download the Roam.json for this block to import into Roam from here.
- #42SmartBlock Summary
    - <%JA:```javascript
async function print(s,uid) {
    let reg = new RegExp('\\^\\^(.*?)\\^\\^','g');
  	let ht = '';
  	while (match = reg.exec(s)) {
        ht += (ht=='') ? '' : highlightSeparator;
      	highlight = match[1];
      	if (removeBold)
        	highlight = highlight.replaceAll('**','');
      	ht += highlight;
    if(ht != '') {
    	ht += ' [*]((('+ uid +')))';
   		await roam42.smartBlocks.activeWorkflow.outputAdditionalBlock(ht, false);

async function sortObjectsByOrder(o) {
    return o.sort(function(a, b) {
      return a[0].order - b[0].order;

async function printChildren(o) {
    await print(o.string,o.uid);
    if(o.children) {
  		var b = await roam42.common.getBlockInfoByUID(o.uid,true);
        var c = await roam42.common.sortObjectsByOrder(b[0][0].children);    
        for(var i=0;i<c.length;i++) 
           	await printChildren(c[i]);

//read source page link from parent block
let UID = document.querySelector("textarea.rm-block-input").id;
UID = UID.substring( UID.length -9);
let blockInfo = await roam42.common.getBlockParentUids(UID);
if(blockInfo.length != 1) {
	alert('Nest command under block containing the [[Page Link]] to your highlighted notes');
	return null;
var pageTitle = blockInfo[0][0]['string'].match('\\[{2}(.*)\\]{2}');
if(pageTitle == null) {
	alert('Can\'t find [[Page Link]] in parent block');
  	return null;
pageTitle = pageTitle[1];

var highlightSeparator = prompt('Set text for separating highlights within the paragraph\nFor example " " or " ... "',' ... ');
var removeBold = prompt('Do you want to remove **bolding** of text?\ni.e. Make **TEXT** into TEXT\n[Y]/[N]','Y');
removeBold = (removeBold=='Y' || removeBold=='y') ? true : false;

//query for source page
var rule = '[[(ancestor ?b ?a)[?a :block/children ?b]]]';
var query = `[:find  (pull ?block [:block/string :block/uid :block/order 
                                   :block/heading :block/children])
              :in $ ?page_title %
              [?page :node/title ?page_title]
              (ancestor ?block ?page)]`;
var results = await window.roamAlphaAPI.q(query, pageTitle, rule);
results = await sortObjectsByOrder(results);
for (j=0;j<results.length;j++) {
   await printChildren(results[j][0]);

Layer 5

I don't yet have much practice with Layer 5. This is reserved for the most valuable information, when I want to remix the material from the book following my own logic and create an article or a blogpost. 
Like this post?
Show your support.


  1. Interesting, thank you. Considering to move from just using Readwise Kindle import to your approach, even if seems quite a lot of work. Already struggling with the first step of the Kindle Highlights into Roam via Python

    1. I suggest you search on Reddit. A few month ago there was a discussion about a Python script for importing Kindle notes into Roam that was much more refined compared to my example in the article. is also an excellent service for this purpose.

  2. Hi Zsolt. Is Roam.json still working? Nothing happens when I execute Summary V2 smart block.


    1. hm. I just tested it. I loaded Roam42 and the json to an empty graph and it all worked without any issues.

      Maybe you also have an earlier version of my smartblock in your graph and when you run the smartblock the wrong version is run.

      Can you try loading roam42 and the smartblock to an empty graph and testing there. This link will create an empty local test graph for you:

      This is the JSON I tested this morning (this is simply the link from my article):

  3. Hi, is it possible to run the summarization against a block instead of a page? In my workflow, I don't keep two separate pages between highlights and summaries. I use different blocks under the same page.


Post a Comment

Popular posts from this blog

Showcasing Excalidraw

Conor ( @Conaw ) pointed me to Excalidraw last week, and I was blown away by the tool and especially about the opportunities it opens up for  Roam Research ! It is a full-featured, embeddable sketching component ready for web integration. This post will showcase key Excalidraw features and discusses some of the issues I still need to solve to complete its integration into Roam. I spent most of my free time during the week integrating Excalidraw into Roam. This article will introduce Excalidraw by showcasing its features.

Mind mapping with Excalidraw in Obsidian

Mind-mapping is a powerful tool. In this post I will show you how and when I mindmap with Excalidraw in Obsidian and why mindmapping is such a good tool for Personal Knowledge Management. Like this post? Show your support.

Evergreen Note on Note-taking Strategies and Their Practical Implementations

This is an evergreen note that I will be revisit regularly to develop a comprehensive list of note-taking approaches including their practical implementations in various software tools. This post will serve as an elaborate table of contents, including a brief introductory discussion on the importance of note-taking, followed by a high-level walkthrough of each method. Links to posts and videos with detailed examples and descriptions will follow over the coming weeks and months.

Deep Dive Into Roam's Data Structure - Why Roam is Much More Than a Note Taking App

Which are the longest paragraphs in your graph? Which pages did you edit or create last week? How many paragraphs of text do you have in your database in total? Which pages do you have under a given namesapece (e.g. meetings/)?