去年, Zettelkastenを知り, Org-roamを使い始めて1年が経った.

日本語のツェッテルカステン解説本(TAKE NOTES!)を読んで考えたこと | Futurismo

これはわたしにとってLife Changing なアプリとなったが, 日本語情報が少ないからか, いまいち流行っていないように思う. なので, 1周年を記念して, 感想とTipsをいったんまとめておいて魅力をアピールしたい.

なお, 基本的な機能は書かないつもりだ, エモい(!=キモい)ポエムを書く. というのも, Org-roamの機能についてガッツリ調べたのは1年前であり, ワタシの知識は古い可能性がある. なので, 1年分の独自の思いとTipcsを一旦吐き出す. なお, 元ネタはOrg-roamに書き溜めているものを切り出す. わたしのOrg-roamはデジタルガーデンとして公開している.

https://keido.site/

Org-roamの魅力

わたしはObsidianやLogseqはちょっとしか触ったことがないので, Zettelkasten系のツールの機能比較をすることができないが, これはOrg-roamならではの魅力なのでは?というものを列挙する.

Org-roamはZettelkastenツールではなくハイパーテキスト編集ツール

Org-roamはRoamという名前がついてRoam Researchを連想するからか, Zettelkastenのツールだと思うかもしれないが, Org-roamはZettelkastenではなく, Org-modeのメモ管理を便利にするツール.

具体的には, org-idをOrgファイルやOrg-modeの見出しに割り振って, その見出しを絞り込みifで検索して挿入したり参照することができる. これだけだ. いいかえれば, これはハイパーテキストとハイパーリンクの編集ツールだ. そう, HTML(HyperText Markup Language)作成ツールみたいなものあり, Yahoo geocitiesみたいなサイトを簡単に作ることができる. 時代はWeb3に向かっているがなんとこれはWeb1に向かっている.

それを使いようによってはZettelkastenのようにも使えるが, Wikiのようにもつかうことができる. Emacs hown を使ったことがある人ならこのイメージに近い. 一人お手軽Wikiにつかえるのだ.

Wikiは知っているがZettelkastenをそもそも知らないかもしれない. WikiはWikipediaみたいなもので, 世間一般の知識を客観的に記述するもので, タイトルはたいてい単語となる.

ex.) 📝Emacs | Keido

一方, Zettelkastenは知識ではなく知恵に相当するもので, 自分の主観的な意見, 感想, ポエム, 愚痴などなど…いわばTwitterにおけるツイート. わたしのイメージでは, ツイート3つ分くらいの文字数がちょうどいいような思考の断片であり, さらに独自の工夫?によってその文章を一言で要約するようにタイトルをつけ, さらにタイトルはコロコロ修正updateして適切なものに変えていく.

ex.) 🎓ハッカーの知的生産術の秘密兵器がプレインテキスト | Keido

風になりたい奴だけがOrg-roamを使えばいい

Org-roamの最大の魅力は, なんといってもEmacsとOrg-modeでメモを作成できるところ. Org-roamの魅力はOrg-modeの魅力でありEmacsの魅力.

そのため, もうこの時点でOrg-modeに拒否反応がある人はこの先を読んでも得るものは少ないかもしれない. 大抵の場合はMarkdownでメモ取るだろう. その場合, ObsidianかLogseqをおすすめする.

しかし, EmacsやOrg-modeを使い慣れていれば, 風になって自由闊達にメモを作成することができる.

cf. 風になりたい奴だけがEmacsを使えばいい 2020 | 日々、とんは語る。

見出しごとに柔軟に org-idを振ることができる(org-id-get-create)

普通のZettelkasten系ツールはタイトルを起点にメモを整理するのかもしれない(ここは未調査なので間違っているかも). しかし, Org-roamは必要に応じてorg-idを設定することで, org-roamで管理するものかを柔軟に変更できる.

これがよいところは, 複数のメモをサブツリーという形でツリー状にまとめることができる. メモを作成していて, 小さなTopicsだとまだそれは単体でorg-roamにいれるほどではないのであるTopicsのサブツリーとしておいていくが, だんたん調べものをして追記していてTopicsが大きくなると, org-idをつけて見出しをそれっぽくすることで独立できる.

大きくなったトピックをサブツリーから個別ファイルに分割(org-roam-extract-subtree)

さらには, M-x org-roam-extract-subtreeをつかって, サブツリーから新規ファイルへ取り出すことができる. これによって, ひとつのメッセージやTopicsごとにメモを作成しているメモ数が多すぎになってしまったり,

いちいち新規作成してタグをつけるのがめんどくさかったりする場合は, サブツリーでまとめておいて分量に応じてメモを分割することで管理が用意になる.

タイトルに複数のサブタイトルをつけることができる(org-roam-alias-add)

見出しを元に検索で引っ掛けるが, 見出しにいくつも別の名前をエイリアスでつけることができる.

これによって, ひとつのメモのなかで複数の主張があるときに, それぞれの角度からメモにリンクが貼れる. Wiki的なメモならいいのだが, Zettelkastenのようなメモのとり方だと, 一つの内容に対して引用元で複数のタイトルをつけたいことが結構ある. 先の例だと「風になりたい奴だけがOrg-roamを使えばいい」という見出しを別のメモの文脈では「Org-roamの魅力はOrg-modeの魅力でありEmacsの魅力」としたほうがいいかもしれない.

Org-roamではエイリアスの機能(org-roam-alias-add)で複数のタイトルをつけることが可能.

絞り込みifによる絞り込みとgrep全文高速検索

Emacsのキラー機能のひとつである, るびきち氏anything派生のifで絞り込みができる. これはEmacs使いならばたまらない魅力であることは理解してもらえると思う.

さらに, プレインテキストを操ることに長けるEmacsからはgrepで簡単に単語を引っ掛けてジャンプすることができる. 今はgrepよりもagやripgrepをつかうひとが多いかな?

ただし, 全文検索でメモをひっかけるのはOrg-roamのメンテの失敗で, 通常ならば適切なタイトルやタグをつけたいところ. そのため, 全文検索をするたびにタグを貼り直して2度目はもっと素早く検索できるようにすることが大事.


現在, 拾い物の関数スニペットでのconsult-ripgrepをつかっている.

Using consult-ripgrep with org-roam for searching notes - How To - Org-roam

ただ1年前の情報で, 現在はdeftがいいのかも(未確認).

(defun my/org-roam-rg-search ()
  "Search org-roam directory using consult-ripgrep. With live-preview."
  (interactive)
  (counsel-rg nil org-roam-directory))
(global-set-key (kbd "C-c r s") 'my/org-roam-rg-search)

Org-roam Tech Tipcs

ここからは, 工夫というよりもニッチな小技を紹介していく.

org-journal vs org-roam-dailies

org-roamの組込みJournal機能として, org-roam-diliesというものがある.

これは現状org-roam-diliesはorg-journalの劣化版になっている. なぜならだいたい同じ用途でありzotzorg-agenda周りの機能との連携がorg-journalのほうがいい.

ref. Org-journal vs org-roam-dailies - Troubleshooting - Org-roam

org-roam-captureというクセのある機能

org-roam-captureというorg-roamに合わせたファイルを作成するテンプレート機能がある. それはorg-captureのようであるが, このクセがあるところは, org-captureの記法に似ているものの細部が微妙に違うのでドキュメントを読まないといけない. 参考までにわたしの設定を貼っておく.

独自のポイントは, Org-roamのファイルはすべて単一のディレクトリに入れている. Org-roamの機能でディレクトリ構造をそのままカテゴリに設定してくれる便利な機能があるが, それをつかっていない.

(org-roam-capture-templates
 '(("z" "🎓 Zettelkasten" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "\n#+date: %T\n#+title:🎓${title}\n#+filetags: :CONCEPT:\n")
    :unnarrowed t)
   ("w" "📝 Wiki" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:📝${title}\n#+filetags: :WIKI:\n")
    :unnarrowed t)
   ("t" "🔖 Tag" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:🔖${title}\n#+filetags: :TAG:\n")
    :unnarrowed t)
   ("h" "👨 Person" plain "%?"
    :target (file+head
             "zk/%<%Y%m%d%H%M%S>.org"
             "#+title:👨${title}\n#+filetags: :PERSON:\n")
    :unnarrowed t)
   ("f" "📂 TOC" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:📂${title}\n#+filetags: :TOC:\n")
    :unnarrowed t)
   ("m" "🏛 MOC" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:🏛${title}\n#+filetags: :MOC:\n")
    :unnarrowed t)
   ("i" "✅ Issue" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:✅${title}\n#+filetags: :ISSUE:\n")
    :unnarrowed t)
   ("p" "⚙ Pattern" plain "%?"
    :target (file+head
             "zk/%<%Y%m%d%H%M%S>.org"
             "#+title:⚙${title}\n#+filetags: :PATTERN:\n")
    :unnarrowed t)
   ("d" "🗒 DOC" plain "%?"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:🗒${title}\n#+filetags: :DOC:\n")
    :unnarrowrd t)
   ("k" "🦊 Darkfox" plain "%?"
    :target (file+head
             "zk/%<%Y%m%d%H%M%S>.org"
             "#+title:🦊${title}\n#+filetags: :DARKFOX:\n")
    :unnarrowed t)
   ("b" "📚 Book" plain
    "%?

- title: %^{title}
- authors: %^{author}
- date: %^{date}
- publisher: %^{publisher}
- url: http://www.amazon.co.jp/dp/%^{isbn}
"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:📚${title} - ${author}(${date})\n#+filetags: :BOOK:SOURCE:\n")
    :unnarrowed t)
   ("s" "🎙‍ Talk" plain
    "%?

- title: %^{title}
- url: %^{url}
"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:🎙 ${title} - ${editor}(${date})\n#+filetags: :TALK:SOURCE:\n")
    :unnarrowed t)
   ("o" "💻 Online" plain
    "%?

- title: %^{title}
- authors: %^{author}
- url: %^{url}
"
    :target (file+head "zk/%<%Y%m%d%H%M%S>.org"
                       "#+title:💻${title}\n#+filetags: :ONLINE:SOURCE:\n")
    :unnarrowed t)))

Org-roam管理のsubtreeをfileへ移動

M-x org-roam-extract-subtreeで新規ファイルに移動できる. はじめはサブツリーで書いていてあとから分離したいときは便利.

逆(file->subtree)の方法は調査中…(たぶんorg-refileだとsubtreeなら移動できるがfileまるごとはできない).

urlをorg-link形式にして挿入する

org-web-toolsのorg-web-tools-insert-link-for-urlをつかうと, clipboardにあるurlをorg-link形式にして挿入.

地味な機能でこれ以外にも手段があるかもしれないが, 実はこの関数をorg-roamのメモ作成でヘビーユーズしている. ページタイトルをeww経由でfetchしてくれるのがいい.

https://github.com/alphapapa/org-web-tools

(use-package! org-web-tools
  :bind
  ("C-c i l" . org-web-tools-insert-link-for-url))

見出しに絵文字をいれる(emojify-insert-emoji)

個人的なこだわりではあるものの絵文字はマスト機能.

Org-modeのメモでは, emacs-emojifyのemojify-insert-emojiをつかって絵文字を見出しに設定している. とくにメモの種類よってワケている.

さらに, org-modeのTODOの設定をカスタマイズして絵文字をシュッといれるようにしている.

(setq org-todo-keywords
      '((sequence "✅(c)" "💡(b)" "📍(r)" "🔍(s)" "📊(a)" "🔬(e)" "⚖(k)" "|")
        (sequence "🎓(z)" "📝(m)" "🔗(l)" "⚙(p)" "📜(q)" "👉(h)" "✨(i)" "|")))

メモのつながりは自力で注意深くつける(Mindful linking)

Org-roamの機能でCompletionがあり, 入力補完としてメモのリンクを挿入できる機能があるがこれを使っていない.

https://www.orgroam.com/manual.html#Completion

積極的な理由は, とくにWikiではなくZettelkastenにおいては, 注意深くメモとメモの繋がりを考えることはそれ自体に意味があると思うから.

以下のブログ記事はorg-roamをつかってZettelkastenをしている人の記事だが, わたしはこの記事を熟読してZettelkastenがだんだん理解できた. ここに書いてあったタグのやり方(Mindful linking)に影響を受けている. おすすめ.

How I note

消極的な理由は, プレインテキストのWikiではリンクをいろいろ貼るとorg-exportがおもすぎて大変なことになるから.

代わりにタグ機能はよくつかっている.

Org-roamのバックリンク検索/グラフ表示

まず前提として, バックリンク機能だったりグラフの機能は, 最近流行りのRoam系ツールの機能でオリジナルのzettelkastenではないのでなくてもいい.

デフォルトの機能でorg-roam-buffer-toggleがあり, これでバックリンクを見ることができるが, このバッファを開いたままカーソル移動するととても重いのでわたしは使ってない. 代わりに, consult-org-roam というパッケージをたまに使ってバックリンクをみる. ただ, バックリンク検索自体をあまりつかってない.

同様にして, 無駄に超絶美しくすごいツールでorg-roam-uiがある. これのすごいところは, Emacsの編集に合わせてリアルタイム描写でグラフがグイグイ動いていくところ. おそらくグラフ表示までなら他のツールもあるものの, Emacs連動のリアルタイムグイグイ感が独創的で, ああワタシの頭脳ってこういう仕組みなんだなと感じることは感動ポイント. ただ, org-roam-uiの開発自体が滞っているようなのと, このアプリは動かすと重いので使ってない.

org-anki

これはおまけだが, Wikiのように学んだことを記録したらAnkiに入れておきたい.

org-anki をつかうと, Org-modeとAnkiをつなぐことができる.

今までanki-editorを利用していたものの,その記法とwikiの相性が悪かった(冗長). これならorg-modeのheadlineがそのままつかえるのがよい.

(use-package! org-anki
  :after org
  :custom
  ;; one big deckの原則に従う.
  ;; ref: http://augmentingcognition.com/ltm.html
  (org-anki-default-deck "Default")
  :config
  (define-key org-mode-map (kbd "C-c n A s") #'org-anki-sync-entry)
  (define-key org-mode-map (kbd "C-c n A u") #'org-anki-update-all)
  (define-key org-mode-map (kbd "C-c n A d") #'org-anki-delete-entry))

Org-roamデジタルガーデン公開

ここからは, Org-roamをデジタルガーデンとして公開する方法について. まず, Zettelkastenを外部サイトに公開することをデジタルガーデンという.

Org-roamのノートをサイトに公開するには?

org-publishかox-hugoを利用するのが一般的.

  • ox-publish を用いてOrgファイルをHTMLに変換して公開.
  • ox-hugoを用いてHugo用のMarkdownに変換してHugoで公開.

将来的にはorg-roamやorg-roam-uiでpublishの機能がサポートされる可能性ありだが, 1年経ち, なんの動きもないのでかなり悲観的.

Publishing org-roam-ui · Discussion #109 · org-roam/org-roam-ui · GitHub

Org-roamから生成したサイトまとめ

一年前にブックマークしたものなので, 今はもう少しあるかも.

現在のわたしの運用メモ

現在は更新したorgファイルをその場でorg-hugo-export-to-mdを呼んで変換している.

org-publish方式は更新分だけをexportしてくれてよいと思ったが, メモが2000くらいあると更新をサーチするだけで結構時間がかかるのでやめた.

それにしても, ひとつのorgファイルにたくさんリンクを貼るとexportがとても重くなるので, その点においてもメモ同士のリンクは少なくする代わりにひとつのメモの範囲を狭めたほうがいいかも.

ニコラスルーマンの方法でも, reference noteはせいぜい15個とかと書いてあった気がする.

HugoでBacklinksを表示する

たまたまみつけた例が自分が使っているHugo Book Templateと同じだったので拝借した.

ox-hugoとの合わせ技. ox-hugoをつかってhugo互換のmarkdownを吐き出してhugoのテンプレートをいじって表示させる.

ref. Ox-hugo export all roam to Hugo | Ben Mezger

ローカルの開発モードだとバックリンクを求めるので時間がかる. サイト公開版だと事前にbuildしているので遅くはならない.

org-exportでバックリンクをexport前に挿入

以下はorg-exportをつかってexportするときのバックリンク挿入方法. hooksをつかってorg-export 前に挿入.

(defun my/collect-backlinks-string (backend)
  (when (org-roam-node-at-point)
    (goto-char (point-max))
    ;; Add a new header for the references
    (insert "\n\n* 🔗Backlinks\n")
    (let* ((backlinks (org-roam-backlinks-get (org-roam-node-at-point))))
      (dolist (backlink backlinks)
        (let* ((source-node (org-roam-backlink-source-node backlink))
               (node-file (org-roam-node-file source-node))
               (file-name (file-name-nondirectory node-file))
               (title (org-roam-node-title source-node)))
          (insert
           (format "- [[./%s][%s]]\n" file-name title)))))))

(add-hook 'org-export-before-processing-functions
          'my/collect-backlinks-string)

ref. Export backlinks on Org export - #20 by FloppyEggplant - Development - Org-roam

最後に1年のポエムを蔵出し

WikiやZettelkastenについて1年間ためたZettelメモを蔵出し. ここからはOrg-roamとあまり関係ない.

Twitterの過去のつぶやきが気軽にgrepできないことに大変ムカつく

もう記録では12年前からTwitterはつかっていたはずだった. しかし, あの頃を思い返したいと思っても気軽にデータにアクセスできない.

このことは大変ムカつくことである. 私の感情や思考の全てを貯めようとしていた. 同様なことはEvernoteにも感じている.

プレーンテキストで情報を保存してgitなどで管理, grepで即時にキーワード検索する. この2つは本当に大事な気がする. もうTwitterに自分の思いはかかない.

即時grepがZettelkatenには必須な気がしている. Twitterはgrepできない.

私にとって珠玉の星屑であるZettel NoteをGoogle様はクズのように評価する

デジタルガーデンを公開しても, Google様がほとんどインデックスしてくれない.

わたしの考えるZettel Noteはツイート3つ分くらいのマイクロブログであるが, それはGoogle様からすれば文字数がちょっと少なかったりする. Zettel Noteは他者の知識をなるべく混入させないように気をつけていて, 他者の知識はWikiにまとめている. まるで関数型プログラミングのように.

私にとっては他者のWiki Noteよりも自分のZettel Noteのほうがはるかに価値がある. その一つ一つの断片は私の価値観を構築する珠玉の星屑の輝きを放つメモたちだが, Google様はZettel Noteをゴミクズのように評価する. しかし私はGoogle様のためにZettel Noteを作っているわけではない.

Zettel NoteはよくTwitterやツイートの比喩で捉えることが多いが, もちろん私のZettelはツイートとツイートの間に勝手に広告を挟み込んでくるTwitter様のためでもない.

ぼくのかんがえた最強の知識体系

おそらく, Org-roamがハマる人はごく一部な気がする. いわゆるメモ魔といわれるような, 普通の人はそんなにメモを取らないだろうという異常な衝動に駆られた人がOrg-roamに虜になる気がする.

Org-roamに書き溜めたメモを整理していると無限に時間が溶けていく, しかしそれは楽しいから時間があっという間に過ぎ去る. この体験, Emacsを使っている人には解るのではないだろうか? そう, Emacsの設定ファイルをいじっていると無限に人生の大切な時間があふぉみたいに溶けていくように.

ADHDの特性は興味がすぐにそれてやるべき作業よりも些末な作業にはまり込んでしまう. やるべきタスクがあるのに気づいたらEmacsの設定ばかりいじって時間が溶けるというEmacs沼, これとADHDの相性は抜群である. 底なし沼で日が暮れる.

そういう意味で, 変人EmacsianたちはOrg-roamととても相性がいいと思う. 設定ファイルをいじくり回すように, ぼくのかんがえたえた最強の知識体系をいじくり回す.

強みの収集心とWikiの相性が抜群にいい

ストレングスファインダーにおける強みの収集心とWikiの方法は相性が抜群にいい.

ストレングスファインダーの収集心とは, とにかく好奇心に突き動かされてなにかを集めてしまうのだ. ひたすら夢中で集めまくる, 気づいたらとても多くの時間を費やしていることに驚く. 没頭できる.

そして, この才能のデメリットも強く感じている. 集めた情報が役に立つとは限らない. 自分の付加価値をつけてアウトプットする必要があるのだが, 集めて満足してアウトプットしない. インプットがいつか役に立つと思っているが無価値=お金を産まないことがほとんどである.

ストレングスファインダーの収集心の説明,

ですから、あなたは物や情報を手に入れ、集め、整理して保管し続けます。それが面白いのです。それがあなたの心を常に生き生きとさせるのです。そしておそらくある日、その中に役に立つものが出てくることでしょう。

こうなってほしい.

知識の基礎概論の柱を立てて枝葉末節の知識をリンクしていく

最近なにかを勉強するときに気をつけていること. まずは知識の基礎概念の柱を立てて, それに枝葉末節の知識を結びつけていく. 具体的には, プレインテキストで基礎概念をまとめたメモを作成する. そして各論のメモを基礎概念のメモに結びつけていく.

たとえば,

プログラミング言語を学んでいると, いろいろな思想で設計されてる. その背後にある抽象された概念はなにかということを意識する. それらは基礎概念としていろんな言語に共通してあるものであり, それらをまずは基礎概念のメモとして作成して, それに知識のメモをリンクさせていく.

新しい他者の知識を学んだとき, まず考えるのはこの知識かどのWiki Notesの中に入るかどうか, ということを考える. ちょっとまとめる知識が大きいときは新規作成するが小さければどこかのメモのサブ項目にする. Org-modeにおいてはNoteというのは一つの見出しであるため, このorg-idを降ったものがどこに納まるかを考えること. Wiki Notesを作成してさらに自分の知識を加えたいときはZettel Notesを作成.

今まで本や動画をみて新しいことを学んだとき, そのまま頭の中でほったらかしにしていた. 今は, 新しいことを学んだとき, 手でする肉体的作業としてのWiki/Zettelkastenシステムのリファクタリングがある. ここで注目したいのが, 知識を引き出しに収めるという喩えと, Noteを作成してWikiに収めること, 肉体的カロリー消費を伴う手作業なのだ. メモの句読点を整理したり, フォーマットをきれいにしてリファクタリングするだけで, 知識を整理していることになる. 本を買ったらそれを知識体系という本棚のなかのどこに並べるか考える.

こういうフィジカルな無駄作業を通じて, これが知識を構築することなんだと実感している. 今まではザルすぎたんだよ, いれても流れ去る. 基礎概念へのリンクの数が多くなればなるほど, 理解は深まり知識は強固になっていく. これが, 脳内で起こっている記憶の仕組みなんじゃないだろうか?

この方法を最近実践しはじめてもっと早くやっておけばよかったと思った. 学び始めは楽しくて, 目の前に移る流行の新しいことをどんどんインプットはするものの, 結局それらを振り返った時, いろんなことを取りこぼしているような気がしてならなかった. 基礎は重要ということをおじさんたちはみんないっていたが理解できなかった. おじさんになったのか, やっと自分も理解したかもしれないが, これは早く気づければ気づいただけ良かったかも.

そして大事なことは, プレインテキストであること. 具体的にはMarkdownかOrg-modeで作成すること. ポッと出のWebサービスは15年後に潰れているかもしれない, 昔WorkPressに勉強していたことをOutputしていたが, DBに入ったデータを救出するのはかなり大変だった. Microsoftだって15年後は潰れているかもしれないし最近のルーキーであるVSCodeも一緒に滅びるので結局はEmacsとOrg-modeがよい.