md-writing

Markdown 文書の組み立ての規範。README・docs・リポ内の解説など、Markdown を新しく書くとき、既存の Markdown に節や文書を足すとき、複数の Markdown を組み替えるときに使う。文書の目的、記録との区別、ほかの文書との重複、リンクの置き方、入口を定める。文の書き方は jp-writing に従う。

SKILL.md

GitHub

md-writing

Markdown 文書を何のためにあるかから組み立てる。この skill が持つのは文書の単位の規範で、文の書き方(冗長な言い回し・LLM口調・翻訳調・読点)は jp-writing に従う。日本語で書くときは両方を当てる。

書く前に決めること

その文書が誰のどの問いに答えるかを1文で決める。 書き始める前に決め、書いている間も変えない。

  • 決めた問いに答えない段落は、正しくても書かない
  • 問いが2つ出てきたら、文書を分けるか、片方を別の文書へのリンクにする
  • 同じ問いに答える文書がすでにあるなら、新しく作らずにそちらを直す

記録を書かない

文書には現時点の事実を書く。 何を足したか、以前はどうだったか、どう直してきたかは記録で、git log・PR・Issue に置く。

書く 書かない
いまどうなっているか、どうするか 「〜を足した」「以前は〜だった」「〜に変えた」
なぜそうするか(現時点の理由) 判断に至った経緯、直してきた回数
配るのをやめたものの置き場(読み返す人がいるとき) 「以前の〜は〜に残してある」を節ごとに繰り返すこと

例として示す案件や場面は記録ではない。読み手が手順を自分の場面に当てはめるための材料として残す。

1つの事実は1か所に書く

同じ事実・同じ表・同じ列挙を2つの文書に持たない。 2か所にあると、片方だけが直されて食い違う。

  • 1つの文書を正本に決め、ほかの文書は要約1文とリンクにする
  • リンクの直前に、リンク先の中身を要約し直さない。要約を置くなら1文で、リンク先を開くかどうかを読み手が決められる量にとどめる
  • 同じ文書の中でも、同じ内容の表と節を並べない。表で足りるなら節を消す

リンクの置き方

リンクは読み手が次に開く必要がある所にだけ置く。 書き写さずにリンクで済ませるのは正しいが、どの文にもリンクを付けると本文が読めなくなる。

  • 同じ文書へのリンクは、1つの文書の中で最初の1回にする。2回目からは節の名前を文字で書く
  • どの節も指さない括弧のリンク(「〜である(x.md)」)を置かない。指すなら節まで書く。指す先が無いなら消す
  • 「詳しくは x.md にある」だけの文を段落ごとに置かない。その文書の末尾か冒頭に、次に読むものとしてまとめる
  • 表のセル1つにリンクを詰めない。ほかの表から開けるものは、ここでは名前だけにする
  • 長い文書で、離れた節から同じ文書の別の節を指すリンクは残してよい。途中から読む人がいる

入口を1か所にする

読む人ごとに、最初に何を読むかを示す場所は1か所にする。 ふつうはリポジトリの README である。

  • 索引(docs/README.md など)は文書の一覧と、それぞれが答える問いだけを持つ。入口の案内を繰り返さない
  • 案内(流れを示す文書)と正本(決まりを書いた文書)を分けるなら、案内から正本へリンクする。案内から、全体の構成を示す文書へ戻るリンクも置く
  • 別の場所へコピーして使われる文書は、コピー元を指さない。コピー先だけで読めるようにする

書いたあとの点検

  • 目的との照合:段落ごとに、冒頭で決めた問いに答えているかを見る。答えていない段落は、記録か、別の文書の中身の書き写しであることが多い
  • 重複の洗い出し:同じ表・同じ列挙・同じ主張がほかの文書にないかを grep で探す
  • リンクの数え上げ:文書ごとに、同じリンク先が何回出るかを数える。3回以上なら、最初の1回を残して減らせないかを見る
  • 切れたリンク:相対リンクがすべて解決するかを確かめる
  • 文の点検は jp-writing の「執筆後の点検」に従う

リンクの数え上げと切れたリンクは次のスクリプトで一度に見られる。

python3 - "$@" <<'EOF'
import os, re, subprocess, sys
files = sys.argv[1:] or subprocess.check_output(['git', 'ls-files', '*.md']).decode().split()
for f in files:
    incode, occ = False, {}
    for i, line in enumerate(open(f, encoding='utf-8'), 1):
        if line.startswith('```'):
            incode = not incode
            continue
        if incode:
            continue
        for t in re.findall(r'\]\(([^)\s]+)\)', line):
            path = t.split('#')[0]
            if not path or re.match(r'[a-z]+:', path):
                continue
            occ.setdefault(path, []).append(i)
            if not os.path.exists(os.path.join(os.path.dirname(f), path)):
                print(f'{f}:{i}: 切れたリンク {t}')
    for path, lines in occ.items():
        if len(lines) >= 3:
            print(f'{f}: {path} を {len(lines)} 回指している(行 {lines})')
EOF