デイリーノートとがんばらないTODO管理【Obsidian】
この記事は Unipos Advent Calendar 2025 18日目の記事です。
TODO管理、続かない問題
TODO管理は悩みのタネになりがちです。「TODO管理 続かない」で検索すれば山ほど記事が出てきますし、ツールを変えても方法論を学んでも、結局続かない人は多いのではないでしょうか。
私も、チームのメインタスクは別で管理していて困ることはないのですが、個人の細かいタスク管理が続かないのが悩みでした。
- 余裕ある時に見たい issue
- アンケートの回答
- ちょっとした調べ物
- 後で読みたいドキュメント
こういったものを TODO アプリで管理しようとしても、いちいちアプリを開いて追加したりが面倒で、結局続きません。
どうしたか
Obsidian のデイリーノートに Markdown 形式で TODO を書いて管理するようにしました。
半年ほど続いていて、個人の細かいタスク管理にはこれで十分だと感じています。
以下のようにチェックリスト形式で TODO を書いていて、メモや子の項目もインデントをつけて書いています。
メモは後から追加したり、ちょっとだけ作業したときに追記したりすることが多いです。
# 12月17日のノート
## TODO
- [ ] issue #123 を見る
×× を ○○ したら上手くいきそう
- [x] アンケート回答 https://example.com/survey
- [ ] ○○さんの記事を読む
12月18日のノートを作ると、前日の未完了 TODO が自動で引き継がれるようにしています。
# 12月18日のノート
## TODO
- [ ] issue #123 を見る
×× を ○○ したら上手くいきそう
- [ ] ○○さんの記事を読む
実際の動作はこんな感じです。仕組みは後述します。

なぜデイリーノートか
デイリーノートを使っている理由は以下の通りです。
- プレーンなテキストでシンプル
- ちょうどいいタイミングで目に入る
- 完了した記録も残る
プレーンなテキストでシンプル
シンプル故に追加や編集が楽で、かつ全体感を把握しやすいです。
好きなエディタで編集すると使い慣れたインターフェースで編集できてより快適です。
手書きのホワイトボードなども一定の支持がある手法だと思いますが、後から追記しやすい点でデジタルの方が便利。
また、在宅とオフィスの両方で仕事するので、物理的なホワイトボードや付箋などは使いにくいです。
ちょうどいいタイミングで目に入る
もともとデイリーノート自体もがっつり運用しているわけではないのですが、やったことや気づいたことなどをメモするのには使っていました。
作業の区切りなどで開くことが多く、ちょうどいいタイミングで目に入るのが良いです。
完了した記録も残る
一時期は、単一のファイルで TODO 管理をしていたこともあるのですが、完了したタスクが消えてしまうことに少しもったいなさを感じていました。
「振り返りでも確認したいから一週間は残しておこう」とか考えると、消すタイミングにも悩みます。
デイリーノートにすることで、1日ごとにクリーンになるのと、必要なら遡って確認できるので管理コストが減っていい感じです。
仕組み
別に手動でも運用はできるのですが、面倒なのでデイリーノート作成時に前日の未完了 TODO を自動で引き継ぐ仕組みを作っています。
この仕組みは Templater プラグインを使って実現しています。
スクリプトは AI に書かせたので、真似するにしても自分のスタイルに合わせて作り直すのが良いかもしれません。
どんなことができるのかの参考にしてもらえればと思います。
Templater 自体はファイルの生成を監視しているっぽいので、Obsidian 上でファイルを生成せずとも、外部でファイルを作成しても動作します。
そのため、私は Neovim 上で生成・編集をしています。
デイリーノートのテンプレート
---
id: <%- tp.date.now("YYYY-MM-DD") %>
aliases:
- <%- tp.date.now("YYYY年MM月DD日") %>
tags:
- daily-notes
---
## TODO
<% await tp.user.getPreviousTodos(tp) -%>
## Memo
<% await tp.user.getPreviousTodos(tp) -%> の部分が前日の未完了TODOを取得して展開してくれます。
未完了TODOを取得するスクリプト
Templater のユーザースクリプト機能を使います。以下のスクリプトを _scripts/templater/getPreviousTodos.js として保存します。
async function getPreviousTodos(tp) {
const today = tp.date.now("YYYY-MM-DD");
// 日付からファイルパスを生成
function generateFilePath(dateString) {
const year = dateString.substring(0, 4);
const month = dateString.substring(5, 7);
// ファイルパスは環境に合わせて変更してください
return `daily/${year}/${month}/${dateString}.md`;
}
// 前の日付を取得
function getPreviousDate(dateString) {
const date = new Date(dateString);
date.setDate(date.getDate() - 1);
return date.toISOString().split("T")[0];
}
// 最大30日前まで遡る
let currentDate = getPreviousDate(today);
let attempts = 0;
const maxAttempts = 30;
while (attempts < maxAttempts) {
const filePath = generateFilePath(currentDate);
const file = app.vault.getAbstractFileByPath(filePath);
if (file && file.extension === "md") {
const content = await app.vault.read(file);
// TODOセクションを抽出
const todoSectionMatch = content.match(/## TODO\n([\s\S]*?)(?=\n## |$)/);
if (todoSectionMatch) {
const todoSection = todoSectionMatch[1];
const lines = todoSection.split("\n");
// 未完了のTODO項目とその子項目を抽出
const incompleteTodoBlocks = [];
let i = 0;
while (i < lines.length) {
const line = lines[i];
if (line.trim().startsWith("- [ ]") && line.trim() !== "- [ ]") {
const todoBlock = [line];
const todoIndentLevel = line.length - line.trimStart().length;
i++;
// 子項目も取得
while (i < lines.length) {
const nextLine = lines[i];
const nextLineIndent =
nextLine.length - nextLine.trimStart().length;
if (nextLine.trim() === "") {
i++;
continue;
}
if (
nextLineIndent <= todoIndentLevel &&
(nextLine.trim().startsWith("- [ ]") ||
nextLine.trim().startsWith("- [x]"))
) {
break;
}
if (nextLineIndent > todoIndentLevel) {
todoBlock.push(nextLine);
} else {
break;
}
i++;
}
incompleteTodoBlocks.push(todoBlock.join("\n"));
} else {
i++;
}
}
if (incompleteTodoBlocks.length > 0) {
return incompleteTodoBlocks.join("\n") + "\n";
}
}
}
currentDate = getPreviousDate(currentDate);
attempts++;
}
return "";
}
module.exports = getPreviousTodos;
スクリプトの動作
- 前日のデイリーノートを探す
-
## TODOセクションから未完了タスク(- [ ])を抽出 - 子項目(インデントされた行)も一緒に取得
Templater の設定
- Templater の設定を開く
- 「Script files folder location」にスクリプトのフォルダを指定(例:
_scripts/templater) - デイリーノート作成時にテンプレートが適用されるよう設定
おわりに
Obsidian のデイリーノートを使ったシンプルな TODO 管理の方法の紹介でした。
デイリーノートを使わずとも、プレーンテキストでの管理自体もおすすめなので、TODO 管理に悩んでいる方はぜひ試してみてください。
Discussion
初めまして。
このスクリプトを便利に使わせてもらっています。
1週間ほど前から、完了済みタスクが翌日も消されずに(未完了状態)で表示されるようになってしまいました。
思い当たる節としては、過去にさかのぼって完了済みチェックを入れてしまったことぐらいです。
どうすればよいでしょうか?
残念ながら私が obsidian の利用をやめてしまったためわからないです
過去分は影響しないと思うので、前日分に問題があるかなと思います
思いつくところですと、余計な空白だったりインデントがあると動かないかもしれないです
ご返信ありがとうございます。
過去のファイルの内容について、見返してみます。
その後Geminiに相談してスクリプトを修正してもらいました。
下に貼っておきます。
async function getPreviousTodos(tp) {
const today = tp.date.now("YYYY-MM-DD");
// 日付からファイルパスを生成
function generateFilePath(dateString) {
const year = dateString.substring(0, 4);
const month = dateString.substring(5, 7);
return
Daily/${year}/${month}/${dateString}.md;}
// 前の日付を取得
function getPreviousDate(dateString) {
const parts = dateString.split("-");
const year = parseInt(parts[0], 10);
const month = parseInt(parts[1], 10) - 1;
const day = parseInt(parts[2], 10);
}
let currentDate = getPreviousDate(today);
let attempts = 0;
const maxAttempts = 30;
// 完了済みとして確認されたタスク名を記録するセット(履歴遡り時の重複・復元防止)
const completedTaskTexts = new Set();
const collectedIncompleteBlocks = [];
while (attempts < maxAttempts) {
const filePath = generateFilePath(currentDate);
const file = app.vault.getAbstractFileByPath(filePath);
}
return "";
}
module.exports = getPreviousTodos;