github twitter linkedin email rss
A Lightweight Note Setup
Mar 15, 2017
11 minutes read

Note taking is an important skill for anyone to have. Being able to keep a high quality record of what was said in a meeting, a phone, call or anywhere else enhances your ability to make good decisions later. Programmers are no different. We have to attend many meetings frequently. We have to communicate requirements precisely. Dropped action items can tack days onto the critical path of a project.

The only major difference that we Programmers have compared to other professionals is that we have more tools at our disposal. Over the last several years, I’ve worked with a lot of note taking systems. To me, note taking is just an input to a great GTD system (worth its own post.) I’ve always looked for better ways to get thoughts down, capturing the important pieces of information for later. Lately, I think I’m starting to hit on something nice.

I started my career using shorthand from high school debate and sheer line spewing developed in college classes. About two years ago I found Katemats’s Ultimate Guide to Note-Taking. This article had a ton of impact on the way that I process information in a large number of contexts. One of my favorite techniques introduced in her post is the sentence method, branded in one flavor as Rapid Logging, which is a catchier name for the whole thing.

While the flavors of the sentence method vary, they share some things in common:

  • Reliance on shooting off line after line and minimal structuring, with post-hoc processing to structure and store the information.
  • Use of shorthand or other techniques to keep writing to a minimum, allowing the mind to flow.
  • A set of meaningful symbols to emphasize classes of special sentences: tasks, events, etc.

The end result is a minimal note-taking system that’s easy to write, and easy to read. In a meeting it stays out of your way, and within a few minutes after everyone is off the conference call you’ve aggregated important facts and obligations in a way that’s easy to use later.

Markdown: How Programmers Would Rather Write Stuff

Markdown has the right of first refusal to everything I type these days. This blog is pure Markdown. My Trello cards are Markdown. My source code commit messages are in markdown. I write emails in Markdown. My docs are in rst which is spiritually similar to Markdown. Blurring the lines between WYSIWIG and plain text, it offers a lightweight way to add a practical amount of structure to just about anything. Possibly the nicest thing about Markdown is that once you write it, it can be handed over to very slick tools to be beautifully rendered speedily. I can micromanage font weight in my CSS later, this is just about saying what my heading was. The files are tiny, and they look pretty good even if you don’t render them. You don’t need a specific program to edit them. “.md” just seems like a very respectable file extension intrinsically.

Old Ideas in a Shiny New Bucket

I’ve recently been prototyping some scripts that have been improving my ability to function during and after meetings (which I understand at this point is a permanent state.) While similar to rapid logging, my system serves a different purpose. Name-brand rapid logging aims to be a complete solution for organizing your tasks; my system narrows its scope to be a information gathering tool. It emphasizes in-the-moment classification, with after-the-fact processing. I have a small toolbox of helper scripts, plus a little extra notation in markdown notes. Lemme show you how it works.

The Symbols

In rapid logging a small vocabulary of symbols gives meaning to your statements. My system is the same:

  • .“: represents an action, analogous to the empty circle of rapid logging. This is something that needs to be done by me as soon as priorities would allow. The period appropriately evokes a simple statement. This eschews the obvious trap of using the square-bracket [ ] syntax for a markdown check-box as it is far too cumbersome to type in a hurry, and I might get the temptation to go fill them in later (DeATH TO OrG-MOdE! (not really, I like org-mode just fine.)) The point is to mark an action and then go away.
  • <“: represents an action that I need to schedule. This is very similar to the dot, but it has a hard deadline. It points left as if to say “you have to do it before you get to that point way over there.”
  • ,“: represents a dependency. Usually this is going to have someone’s name attached to it, preferably right up front in a smelly bold. The comma appropriately evokes a pause, as if to say “That sounds great ,[pause] but what if you did it instead of me.” I argue that no other single symbol so effectively evokes shirking A.K.A. masterful delegation.
  • @“: represents an event. This is something that is going to happen, but I don’t need to do anything about it necessarily. Good for pointing out when people get back from vacation, birthdays, eclipses, and so forth. I’m not going to explain the selection of this symbol to you, lazy moron.
  • !“: denotes importance. Whatever this is by, it just got heavier.

The File

With my handful of symbols, I’m ready to write notes. We’ll work backwards from an example:

# Just a handy example note.

- Some information.
  - Something a bit more specific.
  - Wait should I even be writing this as a sub-bullet oh well lol
- Guess I'm back down here now.
- Here's something that I need to do. .
- info
- That dog is crazy!
- Everybody's workin' for the weekend @
- **Steve** needs to clear out the back room before poker night ,
  - < Poker night is this weekend!
- info etc.
- Steve's phone number is 555-5555!

An important difference is that Symbols can happen when I think of them: If it occurs to me that I’m making an event entry, it can precede the line. If halfway through a thought I can append the symbol, although always with a space (many items end in periods, but they aren’t actions.) The exception is the “!”. If that ever appears on a line, the line is important.

The Tools

Along with my tweaked markdown, I’ve created some helper scripts that power my workflow.

Quickdraw

If I am ever invited to a meeting with my greatest enemy, I will be ready to take notes first. I wrote a script note that lives in my .zshrc. At a moments notice, I pop open a terminal and run note A Meeting With My Greatest Enemy and boom. I’m in vim. My file has a title. My file has a location (more on this below.) I can take notes. It drops an extra comment in there if I really need to know when it happened.

# A Meeting With My Greatest Enemy
<!-- Created at 2017-03-15T21:19:02-05:00 -->

If I Hang up and my enemy comes back, I can re-invoke note A Meeting With My Greatest Enemy instantly, and drop back in. It includes a note that I’m amending it.

# A Meeting With My Greatest Enemy
<!-- Created at 2017-03-15T21:19:02-05:00 -->
- Steve is a lazy moron!
- I must destroy Steve's crazy dog! .

<!-- Amended at 2017-03-15T21:21:20-05:00 -->
- A new moon rises tonight @

Speedy Structure

The note command not only creates notes. It organizes them. When I rattle off a note, note is smart enough to file it somewhere meaningful. In my ~/.notes folder, note creates a folder for the current date, and files the note away.

.notes
└── 2017-03-15
    ├── a-meeting-with-my-greatest-enemy.md
    └── just-a-handy-example-note.md

If I have the meeting twice in a day, I update the existing document. If I have the same meeting tomorrow, I start a new .md file. I use Ctrl-R note to select topics of recurring meetings using my terminal’s autocomplete features.

.notes
├── 2017-03-15
│   ├── a-meeting-with-my-greatest-enemy.md
│   └── just-a-handy-example-note.md
└── 2017-03-16
    └── a-meeting-with-my-greatest-enemy.md

Fire and Forget

If I’m attending a chain of meetings, I don’t want to have to remember that I took notes at earlier ones. I need to meet in rapid succession, and not worry about missing any information.

The key is the ability to rapidly review. This is where the nr “note review” command comes into play. It scrapes my notes using regexes, and formats a meta report with everything that it finds. Here’s an example:

# Note Report for 2017-03-15
## Actions:
- Here's something that I need to do. .

----------------

- . Steve is a lazy moron!
- I must destroy Steve's crazy dog! .

----------------

## Schedule:
- < Poker night is this weekend!

----------------

- < Reschedule poker night

----------------

## Dependencies:
- **Steve** needs to clear out the back room before poker night ,

----------------

- , Steve still hasn't cleaned out his room

----------------

## Events:
- Everybody's workin' for the weekend @

----------------

- A new moon rises tonight @

----------------

## Important:
- That dog is crazy!
- < Poker night is this weekend!
- Steve's phone number is 555-5555!

----------------

- . Steve is a lazy moron!
- I must destroy Steve's crazy dog! .

----------------

Seperate meetings are divided up with handy horizontal lines, and they appear in the order in which they were last modified. nr is a shockingly naive script. It greps for some hastily scribbled our regexes. I check my nr a few times per day. At the end of the week, I check all of my notes from all time with nr!.

# Global Note Report
## Note Report for 2017-03-15
### Actions:
- Here's something that I need to do. .

----------------

- . Steve is a lazy moron!
- I must destroy Steve's crazy dog! .

----------------

### Schedule:
- < Poker night is this weekend!

----------------

- < Reschedule poker night

----------------

### Dependencies:
- **Steve** needs to clear out the back room before poker night ,

----------------

- , Steve still hasn't cleaned out his room

----------------

### Events:
- Everybody's workin' for the weekend @

----------------

- A new moon rises tonight @

----------------

### Important:
- That dog is crazy!
- < Poker night is this weekend!
- Steve's phone number is 555-5555!

----------------

- . Steve is a lazy moron!
- I must destroy Steve's crazy dog! .

----------------


## Note Report for 2017-03-16
### Actions:

----------------

### Schedule:

----------------

### Dependencies:
- , Even now, one day later, Steve still hasn't cleaned out his room.

----------------

### Events:

----------------

### Important:

----------------

Bonus: instant rendering. nrr and nrr! are the rendered companions to nr and nr!. After dumping their respective reports to $TMPDIR, they open it in chrome. Following this thread turns chrome into a perfectly serviceable reader. Here’s an example of nrr’s output.

Rendered Glory

The Workflow: In Summary

  1. Quickdraw with note as needed!
  2. In a lull, review with nrr
  3. Maybe at the end of the week, have a look back with nrr!

Read your aggregated actions, make sure you haven’t missed adding anything to your more complete GTD-type system, and move on!

The Source

Here’s a complete implementation of all of these tools in Bash/Zsh. Dump them in your ~/.bashrc or ~/.zshrc and fire away. I may do a proper implementation that knows how to handle line wraps, but that’ll be a new post someday if I get around to it :). Dependencies include grep, date, mkdir, and xdg-open which should invoke chrome (or however you prefer to view rendered markdown) on .md files. Make sure $EDITOR is set to what you like to use. Lemme know what you think!

# Where to quick-add notes.
NOTE_DIR="$HOME/.notes"

function note()
{
  title="$@"
  filename=$(echo $@ | sed 's/ /-/g;s/\(.*\)/\L\1/g')
  note_path=$NOTE_DIR/$(date -Id)/$filename.md
  mkdir -p $(dirname $note_path)
  if [ -f "$note_path" ]; then
    printf "<!-- Amended at $(date -Is) -->\n" >> $note_path
  else
    printf "# $title\n<!-- Created at $(date -Is) -->\n" > $note_path
  fi
  $EDITOR $note_path
}

function notereview {
  day=$(date -Id)
  if [ ! "$1" = "" ]; then
    day=$1
  fi
  day_folder="$NOTE_DIR/$day"
  for file in $(ls --sort=time --reverse "$day_folder"); do
    cat "$day_folder/$file"
  done
}

function notefilegrep() {
  file=$1
  pattern=$2

  if grep -Eq -- "${pattern}" $file; then
    grep -E -- "${pattern}" $file | sed 's/^ *-/-/g'
  fi
  echo
  echo '----------------'
  echo
}

function notegrep (){
  day=$1
  pattern=$2

  day_folder="$NOTE_DIR/$day"
  for file in $(ls --sort=time --reverse "$day_folder"); do
    notefilegrep "$day_folder/$file" $pattern
  done
}

function notedeps {
  notegrep $1 '(- [,]| [,] *$)'
}

function notesched {
  notegrep $1 '(- [<]| [<] *$)'
}

function noteact {
  notegrep $1 '(- [.]| [.] *$)'
}

function noteevent {
  notegrep $1 '(- [@]| [@] *$)'
}

function noteimp {
  notegrep $1 '- .*[!]'
}

function nr {
  day=$(date -Id)
  if [ ! "$1" = "" ]; then
    day=$1
  fi

  echo "# Note Report for $day"
  echo "## Actions:"
  noteact $day | sed 's/^#/###/g'
  echo "## Schedule:"
  notesched $day | sed 's/^#/###/g'
  echo "## Dependencies:"
  notedeps $day | sed 's/^#/###/g'
  echo "## Events:"
  noteevent $day | sed 's/^#/###/g'
  echo "## Important:"
  noteimp $day | sed 's/^#/###/g'
  echo
}

function nrr {
  day=$(date -Id)
  if [ ! "$1" = "" ]; then
    day=$1
  fi
  tmpfile="$TMPDIR/$day.md"
  nr $day > "$tmpfile"
  xdg-open $tmpfile
}

function nr! {
  echo "# Global Note Report"
  for day in $(ls $NOTE_DIR); do
    nr $day | sed 's/^#/##/g'
  done
}

function nrr! {
  tmpfile="$TMPDIR/global.md"
  nr! > "$tmpfile"
  xdg-open $tmpfile
}

Back to posts


comments powered by Disqus