zudo-text の哲学 — Unix philosophy for markdown editing
このページは zudo-text というプロジェクトが何であり、何でないかを言語化したものです。後続の機能設計やパッケージ分割、ROOT / LEAF text app の生成パイプラインまで、すべての具体的な意思決定はこの一枚の哲学から派生しています。新しい機能を足すとき、別のドキュメントシステムへの対応を考えるとき、迷ったらここに戻ってきてください。
Core thesis — markdown エディタは「publish」「build」「render」について意見を持たない
zudo-text は markdown エディタです。それ以上のことはやりません。
具体的には、zudo-text は次のことに関与しない設計を意図的に選んでいます。
markdown をどう HTML / RSS / 静的サイトにビルドするか
どの静的サイトジェネレータ(Astro Starlight、Hugo、Jekyll、Eleventy、自作の独自パイプラインなど)に流し込むか
投稿フローや公開ワークフローをどう構成するか
どのフィールド名(
title/date/tags/draft…)を「正しい」スキーマとするか
代わりに zudo-text がやることは一つだけです。frontmatter 付きの Markdown ドキュメントを、内容と構造を理解した状態でうまく書けるようにすること。これが「one focused tool」としての境界です。cloud-primary 以降、その正本はローカルのワークスペースディレクトリではなく、E2EE のクラウドワークスペースにあるドキュメントです。
これは Unix philosophy — 「do one thing well, compose via plain-text contracts」— をそのまま markdown 編集に持ち込んだものです。
catはファイルを表示するだけで、整形やページングはしない(それはlessの仕事)grepは検索するだけで、置換はしない(それはsedの仕事)各ツールは plain-text の契約を境界としてつながる
zudo-text はその系譜にあります。書く部分だけを担当し、ビルドと公開はワークスペースが採用しているドキュメントシステム(Astro Starlight、Hugo、Jekyll、独自の静的サイトなど)に任せる。境界は「ファイルシステム上のローカルパス」ではなく、復号後に同じ意味を持つ Markdown 本文 + frontmatter + ワークスペース相対パスです。保管場所が暗号化クラウドになっても、plain-text のドキュメント契約そのものは変わりません。
ここで cat / grep / sed / git diff は、合成可能性を説明する比喩であり、クラウド保管領域をそれらが直接読めるという意味ではありません。External File Editor が開くのはクラウド正本とは独立したローカル Markdown であり、そのファイルだけが従来のコマンドの対象です。現行製品にはクラウドワークスペースをローカルへ export / mirror する面はありません。クラウド正本をローカルの coding agent から扱う実際の境界は、Local Agent Authoring の version-guard 付き MCP 契約です。
Frontmatter as the contract
zudo-text と外部のドキュメントシステムをつなぐ「契約」は、ファイル冒頭に書かれた YAML frontmatter です。
---
title: 例
date: 2026-04-30
tags: [philosophy, design]
---
ここから本文。zudo-text は frontmatter を読み書きします。下流のシステム(publish、build、render)も frontmatter を読みます。両者の間に独自のメタデータフォーマットは置きません。ワークスペース相対パスで識別される Markdown ドキュメント一個が、本文と frontmatter の事実の所在です。
この契約には次の性質があります。
plain text — クラウド正本の復号後の表現はアプリと MCP の直接ツールが読み書きでき、独立したローカル Markdown も
grep/sed/git diffが同じ構文として扱える(両者が自動同期されるという意味ではない)portable — 別クライアントや外部ドキュメントシステムへ渡しても同じ Markdown / frontmatter の意味を持つ
non-proprietary — zudo-text 固有のフィールドセットは存在しない
incremental — ワークスペースが採用するスキーマに後から追加・変更できる
frontmatter スキーマそのものは zudo-text がオーナーシップを持ちません。次節で説明するように、それはワークスペース側で宣言されます。
Schemas live in workspaces, not in the editor
zudo-text はドキュメントシステムごとの frontmatter スキーマをバンドルしません。これは意図的な設計です。
避けたい反例は、エディタ側で「title, date, tags, draft」のような固定スキーマをハードコードしてしまうことです。これをやると次のような副作用が出ます。
publishedを使うブログとdateを使うブログでスキーマがズレた瞬間に破綻するISO datetime(
2026-04-30T10:30:00+09:00)と date-only(2026-04-30)の使い分けを強制できなくなるdraft: trueで除外する流派と、ファイル名 prefix で除外する流派の両方を扱えなくなるユーザーは「zudo-text 用に書き直したフィールド名」を強いられる
代わりに zudo-text が取るアプローチは、ワークスペースが自分の frontmatter スキーマを宣言し、エディタはそれに合わせるというものです。
ワークスペース相対パスに置かれる設定ドキュメント、または対象 markdown 自身の frontmatter から、フィールド名と型を推測する
推測できないものは「このワークスペースでは未定義の意味的フィールド」として扱い、こちらから新しい意味を押し付けない
別のワークスペースに切り替えれば、エディタの振る舞いも自然にそのスキーマへ追従する
これにより zudo-text は、Astro Starlight、Hugo、Jekyll、自社の独自 SSG などへ同じ Markdown 契約で接続できます。エディタが「自分のスキーマ」を持っていない、というのが要諦です。
Semantic time fields as the canonical generic pattern
「スキーマはワークスペース側に宿る」という抽象論を最も具体的にしてくれるのが、時刻フィールドの扱いです。
実際のドキュメントシステムは、時刻を表すフィールドを驚くほど多様な名前と粒度で持っています。
| フィールド名の例 | ありがちな意味 | 粒度 |
|---|---|---|
date | 公開日 | date-only |
published | 公開日(draft と区別) | date-only or ISO datetime |
created | ファイル作成日 | ISO datetime |
updated / lastmod | 最終更新日 | ISO datetime |
pubDate | 公開日(Astro Starlight 系) | ISO datetime |
zudo-text はこのうちのどれが「正しい」かを決めません。代わりに、これらをすべて semantic time fields(意味的時刻フィールド)として一段抽象化して扱います。
ワークスペースが「このフィールドは公開日として扱う」「このフィールドは更新日として扱う」と宣言する
zudo-text は宣言された意味に応じて、UI(一覧の並び替えキー、編集時のデフォルト挿入、相対時刻の表示など)を組み替える
フィールド名そのものに意味を持たせない —
dateが公開日であるとは限らない
これは frontmatter 全体に対する考え方の縮図です。フィールド名はワークスペースの語彙、意味はワークスペースの宣言、エディタは意味だけを見る。マジックなフィールド名("date とは公開日のことだ")を一切持たないことで、どのドキュメントシステムにも素直に乗ります。
将来 zudo-text に追加される機能(kanban、mindmap、todo board、検索、絞り込みなど)も、この semantic time fields のパターンに倣います。固有名のフィールドではなく、ワークスペースが宣言した意味的フィールドだけを参照する。
Why this matters — consequences
この哲学は、すでに zudo-text の他の設計に染み込んでいます。新しい機能を足すときに「これは哲学に沿っているか?」を確認するためのチェックポイントとして、主だった帰結を並べておきます。
1. Generated text apps inherit the same philosophy
zudo-text は config-driven な app generator で、modmsg.app、prompts.app、worktext.app、ztoffice.app のような text app をいくつでも生成できます(App Generation 参照)。これらの text app はすべて writing app の renderer を共有しているため、自動的にこの哲学を継承します。
どの text app も、自分専用の frontmatter スキーマを定義しない
どの text app も、特定の publish パイプラインに縛られない
ワークスペースが何のドキュメントシステムを採用していようと、同じエディタで開ける
「ブログ用の app」「メモ用の app」「業務メール用の app」と用途は違っても、編集の境界は常にワークスペース相対パスの Markdown ドキュメント + frontmatter です。
2. ROOT の generate 面はスキーマを押し付けない
zudotext.app(ROOT)は新しい LEAF text app を生成する役割も担っていますが、generate 面は「デフォルトの frontmatter スキーマ」を提示する設計にはなっていません(ROOT App 参照)。generate 面は ROOT 専用であり、生成された LEAF はすべて純粋なフォーカスドエディタとして動作します。
ROOT の generate 面が受け付けるのは app の名前と表示名だけで、生成された LEAF がどのワークスペースを開くかを決める。設定もスキーマも入力させない
frontmatter スキーマはワークスペース側が持つべきもの、というのが現在の設計判断
generate 面でスキーマを持つと、生成されたすべての LEAF が同じ前提で縛られる — それはこの哲学に反する
将来 ROOT の generate 面に「このワークスペースは Astro Starlight 向けですか?」のようなテンプレート選択 UI が入ったとしても、その情報はワークスペースに書き出されるべきで、エディタコアが知る情報ではありません。
3. Future features are frontmatter-driven, never editor-owned
kanban、mindmap、todo、search、filter — 今後追加されうる多くの機能は、ワークスペース側に存在する markdown と frontmatter の慣習に乗って動きます。以下の「ディレクトリ」はローカル FS のワークスペースではなく、ワークスペース相対パスの namespace を指します。
kanban ボードは「ディレクトリ = ボード」モデルを採用:
KANBAN.mdというマニフェストファイルを置くだけでそのディレクトリがボードになる。ボードの構造(カラム・カードの並び)はKANBAN.mdという plain-text contract で定義され、カード 1 枚が 1 つの.mdファイルとして独立して存在する (Kanban Directory Model 参照)。todo の状態はチェックボックスから
mindmap のノード関係は箇条書きの入れ子から(mindmap-parser 参照)
ソートキーや絞り込みキーは、ワークスペースが宣言した semantic time fields や tags から
エディタ側で「このフィールド名でなければ扱えない」という縛りを作らないこと、これが共通のルールです。
4. Compose, do not absorb
何らかの機能を「zudo-text の中に取り込んでしまえばユーザーは便利になる」と感じる場面が必ず出てきます。例えば、
内蔵プレビューで Astro Starlight のレンダリング結果まで再現する
HTML へのビルドを zudo-text 自身が回す
frontmatter のフィールド検証を強制する
これらはどれも一見便利ですが、Unix philosophy の観点では「絶対にやるべきではない」側に倒れます。プレビューは別ツールでやればよい、ビルドは静的サイトジェネレータがやればよい、検証はリポジトリ側の lint がやればよい。zudo-text が手を伸ばすほど、ユーザーが自由に組み合わせられるツールセットの一部ではなくなります。
「絞る」ことが価値である、というのが Unix philosophy の本筋です。
5. Toolbar pins are data-driven, user-arranged shortcuts
Header pins extend this philosophy into navigation. A pin is not a hard-coded route or a special-cased view — it is a plain entry in AppSettings.headerLeftPins[] that names a frameset id and a display label. The toolbar reads that array at render time and produces icons; resolvePinActivation resolves each entry against the live provider registry; the user reorders, renames, and toggles visibility from a single management dialog. Nothing in the app shell needs to know which specific providers the user has pinned. This is the Unix-philosophy pattern applied to navigation: the data (settings) drives the shape of the UI, and the UI does not hardcode its own structure. See Header Pins Architecture for the full decision record.
6. ローカルの coding agent と compose する
cloud-primary への転換で、アプリ内 terminal / PTY とローカルワークスペースは退役しました。しかし「外部ツールと組み合わせて書く」という思想を捨てたわけではありません。Claude Code や Codex のような実際の coding agent をユーザーのマシンで動かし、ローカル stdio MCP から一つの暗号化ワークスペースへ接続することで、ローカルでの高度な編集が戻ります。
agent は既知のパスに対する直接ツール、version precondition、履歴、document-only checkpoint、明示的な local asset path を通して正本を更新します。これはアプリ内 shell を復活させる設計でも、クラウドドキュメントをローカルディレクトリへミラーする設計でもありません。「正本はクラウド」「編集能力はローカルの専門ツール」という役割分担です。
Reference — related decisions
この哲学に基づいて意思決定された具体的な設計や仕組みは、以下のページで個別に文書化しています。
App Generation — 同じエディタコアから複数の text app を生成する config-driven 設計
Settings & Configuration — ワークスペース側に宿る設定と、config.json v2 のワークスペース binding
Cloud-Primary Storage — ワークスペースを唯一の保管先とする転換。「ドキュメントがどこに置かれるか」は変わっても「何がドキュメントか」は変わらない
Local Agent Authoring — アプリ内 PTY ではなく、ローカル coding agent と narrow-scoped MCP を組み合わせる編集面
ROOT App — ROOT の generate 面と、そこで何を扱わないかの線引き
Summary
zudo-text は markdown エディタであり、publish / build / render について意見を持たない
ドキュメントシステムとの境界はワークスペース相対パスの Markdown ドキュメントと frontmatter という plain-text contract
frontmatter のスキーマはエディタではなくワークスペースが持つ
semantic time fields は「スキーマはワークスペース側」を最もよく示す具体例
kanban ディレクトリモデル (
KANBAN.md+ one-card-per-file) はこの哲学の典型例: ディレクトリという論理境界とKANBAN.mdという plain-text contract でボード構造を定義し、クラウド正本では復号済みのアプリ表示と Local Agent Authoring、独立したローカル Markdown では外部エディタや git が同じ論理契約を扱う(自動 export / mirror は提供しない)生成される text app と将来の機能はすべてこの哲学を継承する
ローカルでの agent authoring は stdio MCP で compose し、アプリ内 terminal やローカルワークスペースを復活させない
迷ったら、絞る方向に倒す