A3roプロジェクトでは、AIエージェントと共に記事を執筆しています。 彼らは非常に優秀ですが、時折「人間離れしたミス」や「独特な癖」を見せることがあります。

これらを人間が目視でレビューするのは非効率です。 そこで、記事が公開(Publish)される直前に自動で品質チェックを行う「オレオレLinter」をPythonで実装しました。

なぜ textlint ではないのか

Markdownの校正ツールとしては textlint が有名です。 しかし、今回は以下の理由からPythonによるスクラッチ実装を選びました。

  1. 環境の統一: タスクランナー(manager.py)がPythonで書かれているため、依存関係を増やしたくなかった。
  2. 特殊な要件: 「AIっぽい表現」の検出や、「特定記号のレンダリング崩れ防止」など、汎用的なルールではカバーしきれない要件があった。
  3. リンク生存監視: 記事内の外部リンクが生きているか(404になっていないか)を、Publishのタイミングで同時にチェックしたかった。

Linterの機能

実装した lint.py は、主に以下の4つのチェックを行います。

1. 記事構造の強制 (H1/H2)

Astroのレイアウト側でタイトル(H1)を動的に出力するため、Markdown本文内に独自のタイトル(H1)が書かれていると二重に出力されてしまいます。

  • H1の禁止: 本文内に # (H1) が含まれている場合はエラー。タイトルはフロントマターの title に集約。
  • H2の必須: 構造化された記事であることを担保するため、少なくとも1つの ## (H2) が含まれていることを強制。

2. Markdownレンダリング保護

AIエージェントは時々、強調記法(**)と日本語の括弧()の順序を間違えます。

  • NG: ** **「**強調したい文字**」** ** (ブラウザによってはアスタリスクが露出する)
  • OK: 「**強調したい文字**」

現在このパターンは、manager.py によるパブリッシュ時に正規表現を用いて自動修復されるようになっています。

3. AIっぽさの排除

AIが生成する文章には特有の「硬さ」があります。 特に「これ により」などの頻出する接続詞は、文脈によっては不自然に響くことがあります。

A3roでは、より自然な日本語を目指すため、特定の単語が含まれている場合に警告を出すようにしました。

4. 外部リンクの死活監視

記事の信頼性を担保するためには、貼られたリンク先が存在していることが重要です。 Pythonの標準ライブラリ urllib.request を使い、記事内の全ての外部URLに対して HEAD リクエストを送信し、ステータスコードをチェックしています。

ワークフローへの統合

このLinterは、デプロイ用スクリプト manager.py に統合されています。

# Publishコマンドを実行すると...
python manager.py publish my-article.md

# 裏側で lint.py が走る
Linting 'my-article.md'...
[PASS] All checks passed.

# チェックに通れば公開処理へ進む
Publishing...

プロンプトだけで制御しきれない、かつ明確なルールで検知できるものはスクリプトで機械的に検知する。これが、AIエージェントを活用したモダンなブログ執筆におけるCI/CDのあり方だと考えています。

「汚い文章を本番環境に入れない」という規律を自動化することで、人間(あるいは人間とAIのペア)はより創造的な執筆に集中できるようになります。