Cursorで「ドキュメントの鮮度」を数学的・構造的に永続化する:コードベース追従型AIドキュメンテーションの完全自動化アーキテクチャ
システムが成長する過程で避けて通れない最大の敵、それは「ドキュメントの腐敗(Documentation Rot)」です。実装コードが更新された瞬間から、README、OpenAPI仕様書、アーキテクチャ設計書は過去の遺物へと劣化を始めます。開発者が手動でドキュメントを更新するという運用は、人間のモチベーションと注意力に依存しているため、遅かれ早かれ必ず破綻します。
本記事では、AI特化エディタ「Cursor」のコンテキスト解析エンジンを極限まで活用し、コードの変更を検知してドキュメントを決定論的に自動更新するパイプラインを構築します。単なるローカルエディタ上のAIアシストにとどまらず、`.cursorrules` による厳密な出力制御から、CI/CD(GitHub Actions)およびDockerコンテナでのヘッドレス自動生成に至るまで、ドキュメントの鮮度を100%に保ち続けるためのエンタープライズグレードのアーキテクチャを完全解説します。
—
1. ドキュメント自動同期の全体アーキテクチャ
コードからドキュメントを自動生成・更新する際、ナイーブに「コード全体とドキュメント全体をLLMに投げる」アプローチをとると、コンテキストウィンドウの破綻、トークンコストの暴増、そしてハルシネーションによるドキュメントの破壊を引き起こします。
これを回避するため、本アーキテクチャでは「ローカル開発時の対話型更新」と「CI/CDパイプラインによる無人非同期更新」を二重化し、セマンティックな差分(ASTレベルの変更)のみをトリガーとするパイプラインを設計します。
[開発者] (Cursor IDE)
│ – コード修正 (e.g., APIスキーマ変更)
│ – .cursorrules に基づくリアルタイムローカル更新検証
▼
[Git Push / Pull Request]
│
▼
[GitHub Actions Runner (Docker Container)]
│ 1. AST/Git Diff抽出 (変更されたシンボルと関連コンテキストを限定)
│ 2. Headless Context Generator 実行 (.cursorrules のプロンプト注入)
│ 3. API経由でLLMを叩き、ターゲットドキュメント(README/OpenAPI)の差分のみ再構築
│ 4. Validation Engine (OpenAPI Lint / Markdown Syntax Check)
│
├─► Valid: ドキュメント修正コミットをPRに自動プッシュ / ブランチ保護ルールクリア
└─► Invalid: CIエラーとしてブロック & ログ出力
—
2. `.cursorrules` によるドキュメント記述スタイルの絶対制御
Cursorの強みは、ワークスペースルートに配置された `.cursorrules` を通じて、LLMの推論プロンプト層に対して強力なシステム制約を課すことができる点にあります。ドキュメント生成においてLLMに与えるべきは「自由度」ではなく「厳格なプログラマブル制約」です。
以下は、コードベースの変更からドキュメントを再構築する際に、ハルシネーションを排除し、フォーマットを完璧に維持するためのプログラマブル `.cursorrules` の決定版です。
`.cursorrules` 設定例
{
“instruction_version”: “2.0”,
“context_awareness”: {
“ast_parsing”: true,
“resolve_imported_types”: true,
“ignore_patterns”: [“node_modules/“, “dist/“, “build/”, “.test.ts”]
},
“rules”: [
{
“id”: “doc-sync-readme”,
“target_files”: [“src//.ts”, “src//.py”, “src//.go”],
“documentation_output”: “README.md”,
“conditions”: [
“EXPORTED_SYMBOL_CHANGED”,
“CLI_ARGUMENT_CHANGED”,
“ENVIRONMENT_VARIABLE_CHANGED”
],
“prompt_instructions”: [
“1. あなたは厳格な技術文書コンパイラです。思考プロセスの会話文(’はい、分かりました’など)は一切出力してはなりません。”,
“2. README.md の変更は、コードベースの実際の変更(Git Diffおよび型定義の変更)に直接紐づくセクションのみに制限してください。”,
“3. API仕様、環境変数表、CLIコマンドフラグのテーブル構造は、コード内のAST構造体から抽出した型定義と1:1で完全一致させてください。”,
“4. 変更がないセクションのテキストや既存の文章表現を不必要に書き換えないでください(Diffの最小化原則)。”,
“5. 新規パラメータが追加された場合、型、デフォルト値、必須/オプショナルのフラグ、説明文をMarkdown形式のテーブルに正確にマッピングしてください。”
]
},
{
“id”: “doc-sync-openapi”,
“target_files”: [“src/controllers//.ts”, “src/routes//.ts”],
“documentation_output”: “docs/openapi.yaml”,
“conditions”: [“HTTP_ENDPOINT_CHANGED”, “REQUEST_RESPONSE_SCHEMA_CHANGED”],
“prompt_instructions”: [
“1. TypeScriptの型定義(Zod Schema, DTOクラス等)から、OpenAPI 3.1.0 互換のYAMLを部分更新してください。”,
“2. アノテーションやJSDocコメント(@summary, @description, @deprecated)が存在する場合は、それを優先的にOpenAPIのsummary/descriptionフィールドに昇華させてください。”,
“3. スキーマの破壊的変更(Breaking Change)が発生した場合は、変更理由を ‘x-breaking-change-notes’ 拡張フィールドに記録してください。”
]
}
]
}
—
3. コンテキスト最適化:セマンティック・ディフ抽出スクリプト
LLMに広大なコンテキストを丸ごと投げると、Token予算が枯渇し、注意力の拡散(Lost in the Middle現象)を引き起こします。ドキュメント更新に必要なのは「変更されたコード」と「その変更が影響するドキュメントの該当箇所」のみです。
以下のPythonスクリプトは、Gitの差分から変更された関数・クラス・型定義のASTシンボルを特定し、最小限かつ高密度な「ドキュメント更新用コンテキストペイロード」を生成します。
`scripts/build_doc_context.py`
!/usr/bin/env python3
“””
ASTおよびGit Diffに基づき、ドキュメント自動更新用最小コンテキストを抽出するスクリプト。
トークン消費を抑え、LLMの出力精度を極限まで高めるための前処理を行う。
“””
import subprocess
import json
import re
import sys
from typing import Dict, List, Any
def get_git_diff() -> str:
“””メインブランチ(Origin/main)とのGit差分を取得する”””
try:
# 変更されたコードの差分を詳細に取得
cmd = [“git”, “diff”, “origin/main…HEAD”, “–“, “src/”]
result = subprocess.run(cmd, capture_output=True, text=True, check=True)
return result.stdout
except subprocess.CalledProcessError as e:
print(f”[ERROR] Git diff の取得に失敗しました: {e}”, file=sys.stderr)
sys.exit(1)
def extract_modified_symbols(diff_text: str) -> List[str]:
“””
Git Diffから追加・修正された主要なシンボル(関数名、クラス名、型定義名)を抽出する
正規表現による軽量なセマンティック解析
“””
# エクスポートされた関数、クラス、インターフェース、型定義にマッチするパターン
symbol_pattern = re.compile(
r’^\+\sexport\s+(?:async\s+)?(?:function|class|interface|type|const)\s+([A-Za-z0-9_]+)’,
re.MULTILINE
)
matches = symbol_pattern.findall(diff_text)
return list(set(matches))
def load_target_document(doc_path: str) -> str:
“””ターゲットとなる既存ドキュメント(README.md等)を読み込む”””
try:
with open(doc_path, “r”, encoding=”utf-8″) as f:
return f.read()
except FileNotFoundError:
return “”
def main():
doc_path = sys.argv[1] if len(sys.argv) > 1 else “README.md”
diff = get_git_diff()
if not diff:
print(“[INFO] コードに変更が検出されなかったため、コンテキスト構築をスキップします。”)
sys.exit(0)
symbols = extract_modified_symbols(diff)
existing_doc = load_target_document(doc_path)
# LLMへ渡す構造化コンテキスト構造体(ペイロード)の組み立て
payload: Dict[str, Any] = {
“target_document_path”: doc_path,
“modified_symbols”: symbols,
“git_diff”: diff,
“current_document_content”: existing_doc
}
# 標準出力にJSONとして吐き出し、次のパイプライン(LLM CLI)へ渡す
print(json.dumps(payload, ensure_ascii=False, indent=2))
if __name__ == “__main__”:
main()
—
4. CI/CDにおける完全自動化:GitHub Actions × Docker パイプライン
Cursorのエンジン(または同様のコンテキスト解析推論モデル)をCI環境で無人で叩き、ドキュメントの同期状態を強制する完全自動化パイプラインを構築します。
このワークフローは、PRが作成・更新された際に自動起動し、コード変更からドキュメントの差分を再計算・自動コミット、または「ドキュメント更新漏れによるCI失敗」を検知してPRのビルドをブロックします。
`.github/workflows/doc-sync-pipeline.yml`
name: “Automated Documentation Freshness Pipeline”
on:
pull_request:
types: [opened, synchronize]
paths:
- ‘src/’ # ソースコード配下の変更時のみ起動
jobs:
sync-documentation:
runs-on: ubuntu-latest
container:
# Node.jsとPython環境、およびGitが事前インストールされた軽量Dockerイメージ
image: mcr.microsoft.com/devcontainers/typescript-node:1-20-bullseye
steps:
- name: Checkout Repository
uses: actions/checkout@v4
with:
fetch-depth: 0 # 全履歴を取得(Git diffの正確な比較のため)
- name: Setup Python Environment
uses: actions/setup-python@v5
with:
python-version: ‘3.11’
- name: Install Dependencies
run: |
python -m pip install –upgrade pip
pip install requests pydantic
# OpenAPIバリデーション用のCLIツール等のインストール
npm install -g @redocly/cli
- name: Build Semantic Diff Context
id: build_context
run: |
# コンテキスト構築スクリプトを実行し、一次保存ファイルに出力
python scripts/build_doc_context.py README.md > doc_context.json
- name: Execute Headless AI Doc Sync
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
# Dockerコンテナ内でパイプラインスクリプトを呼び出し、LLM API経由でドキュメントを再構成
python scripts/headless_doc_generator.py \
–context doc_context.json \
–rules .cursorrules \
–output README.md
- name: Validate Generated Documents
run: |
# 生成されたドキュメントの健全性・構文チェック
echo “[INFO] Validating Markdown format…”
# OpenAPIが存在する場合はLintを実行
if [ -f “docs/openapi.yaml” ]; then
redocly lint docs/openapi.yaml
fi
- name: Auto-Commit Updated Documentation
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: “docs(auto-sync): 自動推論パイプラインによるドキュメント鮮度更新 [skip ci]”
file_pattern: “README.md docs/”
commit_author: “Cursor Doc-Engine
ヘッドレスドキュメント生成スクリプト:`scripts/headless_doc_generator.py`
CI環境で `.cursorrules` の定義に従い、実際にモデル(Claude 3.5 Sonnet等)を叩いてドキュメントの差分のみを上書き適用するPythonスクリプトです。
!/usr/bin/env python3
“””
CI環境で推論を実行するヘッドレスドキュメント同期ジェネレータ。
.cursorrules の制約をシステムプロンプトに注入し、入力されたコードDiffからドキュメントを生成する。
“””
import argparse
import json
import os
import sys
import requests
def run_headless_sync(context_file: str, rules_file: str, output_file: str):
# コンテキストJSONの読み込み
with open(context_file, ‘r’, encoding=’utf-8′) as f:
context_data = json.load(f)
# .cursorrulesの読み込み
rules_content = “”
if os.path.exists(rules_file):
with open(rules_file, ‘r’, encoding=’utf-8′) as f:
rules_content = f.read()
api_key = os.getenv(“ANTHROPIC_API_KEY”)
if not api_key:
print(“[ERROR] ANTHROPIC_API_KEY が設定されていません。”, file=sys.stderr)
sys.exit(1)
# LLMに送信するプロンプトの設計(システムプロンプトの強力なバウンダリ設定)
system_prompt = f”””
あなたは高度に自動化されたソフトウェアドキュメンテーションコンパイラです。
以下の `.cursorrules` に定義されたルールを厳格に順守してドキュメントの更新を行ってください。
【設定ルール (.cursorrules)】
{rules_content}
【制約事項】
- 返答にはMarkdownテキストのみを含めてください。解説、挨拶、前置き、後書きは一切禁止します。
- 送信された ‘current_document_content’ をベースとし、’git_diff’ および ‘modified_symbols’ の変更内容を正確に反映させた完全な更新後テキストを出力してください。
“””
user_prompt = f”””
以下の変更コンテキストに基づき、{output_file} を最新の状態に更新してください。
【変更コンテキスト】
{json.dumps(context_data, ensure_ascii=False, indent=2)}
“””
headers = {
“x-api-key”: api_key,
“anthropic-version”: “2023-06-01”,
“content-type”: “application/json”
}
payload = {
“model”: “claude-3-5-sonnet-20241022”,
“max_tokens”: 4000,
“temperature”: 0.0, # 決定論的(デテルミニスティック)な出力を強制するため0.0に設定
“system”: system_prompt,
“messages”: [
{“role”: “user”, “content”: user_prompt}
]
}
print(f”[INFO] APIへリクエストを送信中… Target: {output_file}”)
response = requests.post(“https://api.anthropic.com/v1/messages”, headers=headers, json=payload)
if response.status_code != 200:
print(f”[ERROR] API呼び出しに失敗しました: {response.status_code} – {response.text}”, file=sys.stderr)
sys.exit(1)
result_json = response.json()
generated_text = result_json[“content”][0][“text”]
# 更新されたドキュメントの書き込み
with open(output_file, ‘w’, encoding=’utf-8′) as f:
f.write(generated_text)
print(f”[SUCCESS] {output_file} の自動更新が正常に完了しました。”)
if __name__ == “__main__”:
parser = argparse.ArgumentParser(description=”Headless Doc Generator”)
parser.add_argument(“–context”, required=True, help=”Context JSON file”)
parser.add_argument(“–rules”, required=True, help=”.cursorrules file”)
parser.add_argument(“–output”, required=True, help=”Output document file”)
args = parser.parse_args()
run_headless_sync(args.context, args.rules, args.output)
—
5. 内部最適化:トークンエコノミクスと更新精度の極限ハック
大規模プロダクトでこの自動化ルーチンを運用する際、実稼働環境で必須となる低レイヤ最適化技法を解説します。
① AST Diffによるノイズ除去(Token Budget Optimization)
一般的な `git diff` には、インデントの調整、フォーマット変更、コメントの修正などの「ドキュメントに何の影響も与えない変更」が大量に含まれます。これらをそのままLLMに投げるとトークン費用が無駄になるだけでなく、LLMの集中力が削がれます。
CI/CDの前処理段階で Tree-Sitter 等のASTパーサーを用いて「シグネチャの変更」「型定義の変更」「Exportされているシンボルの変更」のみを抽出し、以下のようにノイズを除去したコンパクトなDiffに変換してモデルに渡すことで、トークン消費量を最大 80% 削減 できます。
[RAW Diff (1000 lines)]
└─► [Tree-Sitter / Language Server AST Filter]
└─► [Semantic Diff (50 lines): Exported interface API signature modified]
② `temperature: 0.0` とプロンプトのコンパイル化
ドキュメントの自動生成に「AIの創造性」は不要です。創造性はハルシネーションの同義語となります。
推論時のパラメータは `temperature: 0.0` を厳格に適用します。さらに、プロンプト内で「以下のスキーマ変換関数と同等の処理を行え」と命じることで、生成プロセスを数学的な写像(Mapping)へと昇華させます。
③ Redocly / Markdownlint による多重防御(Validation Layer)
AIが生成したドキュメントを直接メインブランチにマージすることは危険を伴います。必ずCIパイプラインの中に「決定論的リンター」を挟み込みます。
- Markdownフォーマット検証: `markdownlint-cli2` を通し、ヘッダー階層の飛躍や閉じ忘れたコードブロックを事前検証。
- API仕様検証: OpenAPIの場合は `redocly lint` を実行し、データ型や必須フィールドが不完全なYAMLのパースエラーを全件検知。
リンターが失敗した場合、生成された差分は破棄され、ビルドエラーとして開発者にアラートが送られます。
—
6. アーキテクチャのまとめ:ドキュメントは「書くもの」から「コードからコンパイルされるもの」へ
本記事で解説したアーキテクチャの導入により、開発者のドキュメント作成に関する認知負荷は限りなくゼロに近づきます。
1. ローカルでの実装: Cursor上の `.cursorrules` が、コード変更中の開発者に対してリアルタイムでドキュメントの不整合をフィードバック。
2. コミット&PR時: セマンティック・ディフ抽出スクリプトがコードの「本質的な変化」のみを抽出し、無駄のない最小コンテキストを形成。
3. CI/CDパイプライン: ヘッドレス環境のLLMコンパイラがドキュメントを再構築し、各種リンターによる厳格な検証を通過した安全な差分のみがリポジトリに自動反映。
ドキュメントをコードと分離された「手作業のメモ」として扱う時代は終わりました。Cursorのコンテキスト認識能力と厳密に設計されたCI/CDパイプラインを結合することで、「コードが更新されれば、ドキュメントは数学的必然として完璧な鮮度を保ち続ける」という開発プロセスの理想郷が完成します。