Markdownを単一ソースにしたタスク管理ツールをVite + React + Monacoで作ってみた
はじめに
最近、個人開発や調べ物などを進める中で
「もう少し雑に扱えて、あとから AI に投げやすいタスク管理が欲しい」
と思うことが増えてきました。
多くのタスク管理ツールは高機能で完成度も高いのですが
- 入力がフォーム前提になっている
- 内部データ構造がツール固有で外に出しづらい
- LLM にそのまま渡せる形では保存されていない
といった点が、少しだけ引っかかっていました。
そこで今回
「人間が書きやすく、LLMが読みやすい」 タスク管理の形を試してみようと思い
Flowmark という小さなアプリを作りました。
Flowmark の基本方針はとてもシンプルです。
- タスクは Markdown でそのまま書く
- Markdown が唯一の正
- UI やビューはすべてそこから自動生成する
Markdown なら人間にとっては雑に書けて
LLM にとってはそのまま文脈付きデータとして扱えます。
この記事では Flowmark を どんな設計で、どのように実装したかを整理していきます。
作ったもの
画面スクショ
- 画像の左側がマークダウン入力画面で、右側がマークダウンを元にタスクを表示
- 「#」で入力したものでタスク分類
- 画面右側のチェックボックスをクリックすると [x]にもできる
Github
(starいただけると嬉しいです…)
Flowmarkは「タスク管理ツール」ではない
Flowmark は、一般的な意味での「タスク管理ツール」ではありません。
Todo アプリやプロジェクト管理ツールというよりも
「思考を止めずに、やることを書き続けるための道具」を意識しました。
多くのタスク管理ツールでは、タスクを追加するだけでも次のような操作が必要になります。
- 入力フォームを開く
- タイトルを入れる
- 期限や優先度を選ぶ
- 保存ボタンを押す
この一連の操作は、一見すると整理されているようで
実際には 「考える流れ」を何度も分断します。
Flowmark が解決したかったのは
「タスクを管理すること」ではなく「タスクを書くこと」です。
発想の転換:まず Markdown を書く
Flowmark の出発点はとても単純です。
人間は、構造化されたフォームより
箇条書きの文章のほうが速く書ける
実際、やることを考えるときはこんな書き方をします。
- バグ直す
- 明日ミーティング
- 記事書く
Flowmark では、この 雑な書き出しを否定しません。
むしろ、それをそのまま「正」として扱います。
- Markdown は人間が書く
- 構造化はツールがやる
- UI は Markdown から常に再生成する
これが Flowmark の思想です。
Flowmark の全体像
UI は非常にシンプルです。
- 画面左:Monaco Editor で Markdown を直接編集
-
画面右:Markdown をパースした Task AST から導出したビュー
(Inbox / Today / All / セクション別) - 保存:IndexedDB
画面右側は常に派生ビューであり、真実は左側の Markdown だけ
という点です。
図解:Flowmark のデータフロー
- 編集は常に Markdown
- UI 操作も最終的には Markdown を書き換える
- 状態は一切分岐しない
技術スタックと構成
- Vite + React + TypeScript(strict)
- Monaco Editor
- monaco-editor
- @monaco-editor/react
- Tailwind CSS
- 永続化:IndexedDB → localStorage fallback
ディレクトリ構成(monorepo-ready、webのみ実装)
flowmark/
docs/ # Codex先生用
packages/
web/
src/
parser/
storage/
ui/
utils/
コア設計
Flowmark の設計原則はこれだけです。
- UI の状態は 常に Markdown から導出
- 右側 UI の操作も 最終的には Markdown を書き換える
これにより
- データモデルの二重管理を回避
- 状態不整合の温床を排除
- デバッグ対象を Markdown のみに限定
できます。
タスク記法
タスクは 1 行 = 1 タスクの Markdown リスト項目です。
- [ ] write blog @2026-01-10 #oss !high ~30m
- [x] fix parser bug @2026-01-07 @15:00 #wbs !!
- buy milk
MVP ルール
- 行頭が
-ならタスク候補 -
[ ]/[x]があれば完了状態に反映 - 未知トークンがあっても 絶対に落とさない
- raw(元行)は必ず保持
トークン一覧(順不同)
以下を入力するとタスクの下側に付属情報が表示されるようなイメージです。
- due:
@YYYY-MM-DD/@today/@tomorrow - time:
@HH:MM - tag:
#word - priority:
!low/!high/!!/!!!→ 0..3 - effort:
~<number>(m|h)→ minutes
1パスでの Markdown パース(セクション導出)
見出しは MVP なので # (level 1)のみ扱います。
セクションは 直前の見出しです。
for (let index = 0; index < lines.length; index++) {
const line = lines[index];
if (line.startsWith('# ')) {
currentSection = line.slice(2).trim() || 'Inbox';
continue;
}
if (!line.startsWith('- ')) continue;
const parsed = parseTaskLine(line, { now });
if (!parsed) continue;
tasks.push({
id: fnv1a32(`${currentSection}\n${normalizeTaskLineForId(line)}`),
raw: line,
section: currentSection,
...parsed,
lineNumber: index + 1
});
}
Monaco Editor を使った理由
Flowmark において Monaco は
単なるエディタ部品ではなく、UX そのものです。
なぜ Monaco か
- VS Code と同じ編集体験
- Undo / Redo / 行操作 / マルチカーソルが最初から揃っている
- コマンド登録とキー割当が強力
- テキストモデルを直接操作できる
なので
「UI 操作」ではなく「テキスト編集」としてタスク管理ができます。
公式リソース
- Monaco Editor 公式
https://microsoft.github.io/monaco-editor/ - GitHub
https://github.com/microsoft/monaco-editor - React ラッパー
https://github.com/suren-atoyan/monaco-react
図解:Monaco を中心にした編集ループ
おわりに
Flowmark は
タスクを「管理」するためのツールではなく、
タスクを「書き続ける」ための道具です。
Markdown を書く行為そのものを中心に据え、
UI は常にそれに従う。
この思想が刺さる人には、かなり快適な体験になるかと思い作ってみました。
本当にこれが良いのか自分でもわからないのでしばらく自分で使ってみようと思います。
Discussion