Ghostchars について
Ghostchars は、テキストや文書内の不可視 Unicode 文字を検出・除去するオフラインツールです。文章の機械的な書き方の傾向も報告し、ネットワーク、テレメトリー、アカウント、実行時依存なしでローカル動作します。
主な機能
- 01文字位置・コードポイント・名前を表示
- 02テキストと対応文書をクリーニング
- 03設定した基準でツリーを検査
- 04機械的な文章の傾向を報告
- 05DOCX、ODT、HTMLに対応
- 06エージェント向けツールを公開
活用シーン
- 01原稿内の不可視文字を検出
- 02DOCX、ODT、HTML文書をクリーニング
- 03CIやコミット前にファイルツリーを検査
- 04原稿の機械的な書き方の傾向を確認
MCP 対応
stdinとstdoutでMCPサーバーを起動でき、clean_text、inspect_text、style_report、check_pathsをエージェント向けのツールとして公開します。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
4掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| bar | enum | いいえ | クリーニングの強度です。"text"(デフォルト)は不可視文字を削除し、タイポグラフィを正規化します。ノーブレークスペースを通常のスペースに、em ダッシュ、en ダッシュ、カール引用符、省略記号を ASCII に置き換えます。人が読むテキストには "text" を使用してください。"default" は不可視文字のみを削除し、タイポグラフィは変更しません。他の場所から引用したテキストにはこちらを使用してください。"max" は見た目が似たキリル文字とギリシャ文字も統合し、NFKC を適用します。文字を書き換えるため、情報が失われます。自分が書いていないテキストに "max" を使用しないでください。default | text | max |
| text | string | はい | クリーニングするテキスト。すでにクリーンな場合は変更せずに返します。 |
| options | object | いいえ | オプションごとの詳細な上書き設定です。bar が基準を設定し、ここでは個々のオプションを有効にすることのみ可能です。特定のオプションが必要な場合を除き、省略してください。 |
| options.nfc | boolean | いいえ | 他の処理を実行する前にテキストを NFC 正規化します |
| options.pua | boolean | いいえ | 私用領域の文字を除去します。これによりアイコンフォントが壊れます |
| options.bidi | boolean | いいえ | 右から左に書くテキストの隣にある場合も含め、双方向テキストのマークと分離子を除去します |
| options.nfkc | boolean | いいえ | 最初に NFKC 正規化します。文字を書き換え、`--nfc` より優先されます |
| options.punct | boolean | いいえ | em ダッシュ、en ダッシュ、曲線引用符、省略記号、マイナス記号を ASCII に変換します |
| options.spaces | boolean | いいえ | ノーブレークスペースなどの特殊な空白を通常のスペースに変換します |
| options.gutters | boolean | いいえ | ターミナルが行頭に描画する引用バー(U+258C から U+258F、U+2502、U+2503)と、その後のスペースを 1 つ除去します。インデントと罫線表は保持します |
| options.collapse | boolean | いいえ | 行内に連続する 2 つ以上のスペースを 1 つにまとめます |
| options.controls | boolean | いいえ | C0 および C1 制御文字を除去します。タブと行末は保持します |
| options.newlines | boolean | いいえ | すべての行末を通常の改行に統一します |
| options.trailing | boolean | いいえ | 各行末尾のスペースとタブを除去します |
| options.aggressive | boolean | いいえ | 結合文字(ゼロ幅接合子、異体字セレクター、タグ文字)を、実際に機能している場合も含めて除去します。これにより絵文字シーケンスや一部の文字体系が壊れます |
| options.confusables | boolean | いいえ | 複数の文字体系が混在する単語内で、ラテン文字に似たキリル文字とギリシャ文字をラテン文字に置き換えます |
| max_findings | integer | いいえ | 検出結果リストと書き換え箇所の上限です。クリーニング後のテキストが切り詰められることはありません。 |
詳細
ghostchars
テキストやドキュメント内の不可視 Unicode 文字や、機械的な文章で使われる句読点を見つけて削除します。すべての処理はお使いのマシン上で実行されます。ネットワーク通信、テレメトリー、アカウントは不要で、実行時の依存関係もありません。
npx ghostchars clean -i notes.md # clean a file in place, atomically
cat draft.md | npx ghostchars inspect # what is hiding: line:col, codepoint, name
npx ghostchars check --bar text # the gate: exit 1 if the tree is dirty
npx ghostchars report draft.md # habits that make a draft read as machine written
npx ghostchars clean -i essay.docx # documents too: .docx, .odt, .html
Node 22 以降が必要です。パッケージ全体は、ランチャーと 3 つのバンドル(CLI、ドキュメントリーダー、MCP サーバー)で構成されています。ドキュメントを指定するかサーバーを起動しない限り、最初のバンドルだけが読み込まれます。
コマンド
clean は標準入力または指定したファイルを読み込み、クリーニングしたテキストを標準出力に書き込みます。-i を指定すると、各ファイルを直接書き換えます。--check を指定すると何も書き込まず、変更が必要な場合は終了コード 1 で終了します。
inspect は疑わしい文字をすべて列挙し、行、列、コードポイント、Unicode 名、およびその文字に作用するフラグを表示します。何も変更せず、該当する文字が見つかった場合は終了コード 1 で終了します。
report は、下書きが機械的な文章に見える原因となる特徴(文の長さの均一性、定型的なつなぎ表現、特徴的な単語、ダッシュの密度、三連セミコロン、曖昧な表現、具体性の不足)を測定します。これは検出器ではなく、確率も出力しません。
check はツリー全体を基準に照らして検査し、変更が必要なファイルと正確な文字位置をすべて表示します。CI やコミット前フックで使うコマンドです。対象範囲と固定設定は ghostchars.json で指定します。
mcp は標準入力と標準出力で Model Context Protocol サーバーを実行するため、エージェントはシェルを介さずに clean_text、inspect_text、style_report、check_paths をツールとして呼び出せます。
help はコマンド一覧を表示し、help <command> は指定したコマンドのフラグを表示します。help --json はインターフェース全体を、機械で読み取れる単一のドキュメントとして出力します。
version はバージョンを表示します。
フラグ
13 個のクリーニングスイッチ、その表記と意味は、基盤となるエンジンが同じである Python の参照 CLI と完全に一致します。
| フラグ | 内容 | デフォルトではない理由 |
|---|---|---|
| (デフォルト) | ゼロ幅スペース、ワードジョイナー、バイトオーダーマーク、ソフトハイフン、不可視の数学演算子、双方向テキスト上書き制御文字、単独のタグ文字、非文字、予約済みのデフォルト無視コードポイント、その他すべての書式制御文字 | |
-a、--aggressive | 重要な役割を担っていても、結合文字を削除します | 絵文字の並び、ペルシア語、インド系文字、地域旗が壊れます |
-s、--spaces | 改行しないスペースやその他の特殊なスペースを通常のスペースに変換します | |
-n、--newlines | CRLF、CR、NEL、LS、PS を通常の改行に変換します | 行末が変わります |
--bidi | 右から左に書くテキストの隣にある場合も含め、双方向テキスト制御マークとアイソレート制御文字を処理します | ヘブライ語とアラビア語が混在するテキストが壊れます |
--controls | タブと行末文字を残し、C0 と C1 の制御文字を処理します | |
--pua | 私用文字を処理します | アイコンフォントの字形が壊れます |
--punct | 全角ダッシュと半角ダッシュ、曲線引用符、省略記号、マイナス記号を ASCII に変換します | 隠蔽ではなく、タイポグラフィの変更です |
--confusables | 異なる文字体系が混在する単語内に限り、キリル文字とギリシャ文字の紛らわしい文字をラテン文字に変換します | 文字を書き換えるため、必要に応じて明示的に有効にしてください |
--nfc、--nfkc | ほかの処理を始める前に Unicode 正規化を行います | NFKC は文字を書き換え、情報を失います |
--gutters | ターミナルが行頭に描画する引用バー(U+258C ~ U+258F、U+2502、U+2503)とその後のスペースを処理し、インデントと罫線で描いた表の行は残します | ディレクトリツリーや枠線も同じバーで行が始まることがあります |
--trailing | すべての行末のスペースとタブを処理します | Markdown の強制改行 |
--collapse | 行内の連続する 2 個以上のスペースを 1 個にします | |
--max | --nfkc が --nfc に優先するため、--nfc 以外の上記すべてを有効にします |
デフォルトのクリーニングは文脈を考慮します。ラテン文字 2 文字の間にあるゼロ幅接合子は削除しますが、家族の絵文字やペルシア語の単語に含まれるものは残します。単独のタグ文字はメッセージへのテキストの埋め込みに使われるため削除しますが、完全な地域旗は残します。英語のテキスト内の左から右マークは削除しますが、ヘブライ語の隣にあるものは残します。-a を指定すると、この判断は無効になります。
オプションは有効にすることしかできません。参照 CLI にもないため、無効にする方法はありません。
3つのバー
バーは名前付きのオプションセットです。人やエージェントは、13個の真偽値ではなく、1つの単語を選択できます。
| バー | オプション | 用途 |
|---|---|---|
default | なし | 不可視文字のみです。正当に必要とされることはありません |
text | -s --punct | 人が読むあらゆるものです。自身の文章にはこのバーを使います |
max | --max の12個 | 紛らわしい文字やNFKCを含むすべてです。情報が失われます |
適用順序は固定されているため、結果は常に予測可能です。
- すべてのオプションをオフにした状態から始めます。
--barを適用します。- 指定されていれば
--maxを適用します。 - 個別のフラグを適用します。これらはオプションをオンにすることしかできません。
そのため、--bar text --collapse は -s --punct --collapse となり、--bar max --punct は引き続き単に max となります。
max は、見た目が似ているキリル文字とギリシャ文字を統合し、文字を書き換えるNFKCを適用します。自分が書いていないテキストには実行しないでください。ゲートバーとしては提供されていません。詳しくは以下の check を参照してください。
ドキュメント
clean と inspect は拡張子でドキュメントを判別し、構造を保って処理します。
| 拡張子 | 処理方法 | 追加フラグ |
|---|---|---|
.docx | パッケージを解凍し、すべてのテキストノードをクリーニングしてから、ZIPを再構成します | --metadata、--rsids |
.odt | ODFのパーツを使って、同様に処理します | --metadata |
.html、.htm | テキストノードのみを対象とします。タグ、属性、スクリプト、スタイルには手を加えません | |
| その他すべて | プレーンテキスト |
--as text を指定すると、どのパスもプレーンテキストとして強制的に処理されます。Pythonの参照CLIが .html ファイルを処理するときと同じ動作です。
-i を指定しない場合、クリーニングしたドキュメントは元のファイルと同じ場所にある <name>.clean<ext> に書き込まれます。または、-o で指定したパスに書き込まれます。
ドキュメントに対する inspect は、連結したドキュメントテキストの文字レポートを出力し、その後、そのテキストの周囲に隠れているものを表示します。具体的には、非表示の範囲、白地に白のテキストや極小のテキスト、変更履歴、コメント、異なるrsid編集セッションIDの数、メタデータフィールド、マクロ、メディアです。--metadata は作成者フィールドを空にし、カスタムプロパティを削除します。--rsids は編集セッションのフィンガープリントを削除します。
非表示の範囲、コメント、変更履歴は報告されますが、削除されることはありません。これらを削除するとドキュメントが変更されるため、削除するかどうかは人が判断します。
対象外:PDF、画像、.pptx、.xlsx、.rtf、.doc、.epub、.pages。check はドキュメントを一切開きません。
check
ghostchars check [--bar default|text] [option flags]
[--config <path>] [--no-config]
[--git|--no-git] [--max-bytes N] [--limit N]
[--fix] [--json] [--verbose] [paths...]
--bar は default と text のみを受け付けます。意図的に max のゲートバーはありません。max はタイポグラフィではなく、対象スクリプトや記号に関わる混同しやすい文字と NFKC を有効にします。また、正当なキリル文字、ギリシャ文字、絵文字を不正とするゲートは、導入した人たちに削除されてしまいます。同じ理由で、デフォルトのバーは default です。タイポグラフィはプロジェクト固有のスタイルであり、明示的に有効にする必要があるためです。
パス引数を指定しない場合、check は git ls-files でファイルを見つけます。そのため、リポジトリですでに使われているものと同じ無視ルールが適用され、新しく追加されていないファイルも引き続き検出されます。リポジトリ外、または --no-git を指定した場合は、代わりにツリーをたどり、node_modules、ビルド出力、仮想環境、および名前がドットで始まるすべてのディレクトリをスキップします。ただし、コーディングエージェントが指示を読み込む次のディレクトリは除きます(.cursor、.github、.claude、.agents、.windsurf、.devin、.gemini、.codex、.clinerules、.continue、.kiro、.roo)。--git を指定すると、パスを指定したかどうかにかかわらず、git が利用できない場合はハードエラーになります。そのため、CI でコンテナごとに処理方法が暗黙に切り替わることはありません。パス引数は常に git から検索するのではなく、ツリーをたどって調べます。そのため、--git <paths> は git が利用可能であることを確認し、"discovery": "walk" を報告します。結果はパス順に並べられるため、出力がディレクトリの順序に左右されることはありません。たどる対象のディレクトリを開けない場合は、標準エラーにエラーを出力して終了コード 2 で終了し、黙って省略することはありません。
拡張子が既知のバイナリ形式である場合、--max-bytes(デフォルトは 2 MiB)を超える場合、先頭 8192 バイトのいずれかに NUL が含まれる場合、または UTF-8 として無効な場合、ファイルは実行を失敗させることなく黙ってスキップされます。コマンドラインで名前を指定したファイルは別扱いです。テキストであると明示したことになるため、コンテンツに関する両方のチェックは適用されず、厳密なデコードの結果が優先されます。デコードに失敗すると、エラーとなり終了コード 2 で終了します。
check <dir> は、別の場所から実行した場合でも <dir> 自身の ghostchars.json を見つけます。作業ディレクトリの隣に設定ファイルがない場合は、指定した各パスから上方向に検索し、そのパスのリポジトリルートで停止します。異なる設定ファイルが適用される 2 つのパスを指定するとエラーになります。1 回の実行でルートは 1 つであり、ピンはそのルートからの相対パスで記述されるためです。--verbose を指定すると、使用された設定ファイルが表示されます。
ghostchars.json
ツリーのルートに配置するか、--config で指定してください。
{
"version": 1,
"surfaces": [
{
"id": "invisibles",
"bar": "default",
"include": ["**/*"],
"exclude": ["vendor/**"]
},
{
"id": "prose",
"bar": "text",
"include": ["**/*.md", "src/messages/*.ts"],
"decodeEscapes": true,
"pins": { "docs/glyphs.md": 12 }
}
],
"maxBytes": 2097152
}
surface には、バー(または options リストのどちらか一方。両方は指定できません)、対象となる glob、およびピンを記述します。どの surface にも一致しないファイルは、まったくチェックされません。除外は、明示的に指定したパスも含め、すべてに優先します。不明なキーがあると、既知のキー一覧を示すエラーになります。そのため、pins の入力ミスが黙って無視されることはありません。
glob で使用できるのは、任意の数のパスセグメントを表す **、1 つのセグメント内の任意の文字列を表す *、および 1 文字を表す ? です。波括弧と文字クラスは使用できません。
decodeEscapes は、ファイルのチェック前に \uXXXX と \u{XXXX} を、それぞれが表す文字に変換します。人が文字列を読むソースファイルでは有効にし、それ以外の場所では無効のままにしてください。コードポイントの一覧には、文字として一致するだけで実際に配布されるわけではないエスケープが多数含まれるためです。
ピン
ピンは、ファイルが意図的に正確に N 文字変更されることを示します。ピンは変更の両方向で適用されます。
| ピン | 測定値 | 結果 |
|---|---|---|
| なし | 0 | 合格。何も出力されません |
| なし | N(0 より大きい) | FAIL changed。すべての文字が一覧表示されます |
| N | N | 合格 |
| N | M(M は N ではない) | FAIL pin-mismatch:M 文字変更されていますが、ピンで指定されているのは正確に N 文字です |
| N(0 より大きい) | 0 | FAIL pin-stale:意図的に変更ありとしてピン留めされていますが、現在は変更がありません。ピンを解除してください |
最後の行は、忘れられがちなケースです。誰かがファイルをひそかに修正したことでピンが古くなった場合に検出できます。
出力
docs/post.md: the text bar would change this file:
docs/post.md:1:26 U+2014 EM DASH
Ghostchars is a text tool<EM DASH>it finds what a reader cannot see.
docs/post.md:2:43 U+200B ZERO WIDTH SPACE
There is a zero<ZWSP>width space in this one.
ghostchars: 1 file would change, 3 scanned
2つのプレースホルダーは実際の文字を表します。このファイル自体が
text の基準を満たす必要があるため、文字をそのまま出力する代わりに
コードポイントを記載しています。
問題のある文字ごとに path:line:col U+XXXX NAME の行を1行出力し、行番号ごとに
ソース行を1回出力します。終了コードは1です。すべてに合格した場合は、次の1行を
出力します。
ghostchars: 3 files pass the text bar。--verbose を指定すると、合格した
ファイル名も出力します。
CI での使用
npx -y ghostchars check --bar text
このステップはこれだけです。CI では決して --fix を渡さないでください。--fix は
問題のあるファイルをその場で修正してから再チェックするため、変更内容を誰も
確認しないまま、ビルドを失敗から成功に変えてしまいます。また、固定された
ファイルはスキップして、そのファイル名を出力します。修正すると、そのファイル
自身の固定が無効になるためです。
ローカルで --fix を実行した後は、ダッシュに関する問題が見つかったファイルを
読み直してください。クリーナーは、2つの単語の間にある em ダッシュをスペース、
ハイフン、スペースに変換します。これは正しい変換ですが、読み心地はよくありません。
該当する位置は、JSON 出力の rewriteSites に一覧表示されます。
--sarif は、同じ実行結果を SARIF 2.1.0 ログとして出力します。問題のある文字
ごとに、その行、列、ソース行を含む結果を1件ずつ出力し、固定の失敗ごとにも
結果を1件出力します。GitHub のコードスキャンでは、これらがプルリクエスト上に
インラインで表示されます。
- run: npx -y ghostchars check --bar text --sarif > ghostchars.sarif || true
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: ghostchars.sarif
終了コード1は問題が見つかったことを意味し、アップロードステップがそれを
アノテーションに変換するため、|| true を指定しています。ジョブも失敗させる
必要がある場合は、通常の check ステップも別に残してください。--sarif と
--json は同じ標準出力に対する2つの形式であるため、コマンドは両方を同時に
指定すると拒否します。
pre-commit フックとしての使用
integrations/pre-commit/pre-commit-config.yaml は、.pre-commit-config.yaml に
貼り付けるブロックです。これは language: node を使う repo: local フックなので、
フレームワークが固定された npm パッケージを独自の環境にインストールし、
リポジトリはクローンされません。CI のステップと同様に、ステージされたテキスト
ファイルを対象に実行し、--fix は決して渡しません。
終了コード
| code | 意味 | 対象コマンド |
|---|---|---|
| 0 | 完了。報告事項なし | すべてのコマンド |
| 1 | 問題が見つかった、変更が必要、またはゲートに失敗 | inspect、clean --check、check、report --fail-on |
| 2 | 要求された実行を完了できなかった:使用方法の誤り、読み取り不能または非 UTF-8 のファイル、不正な設定、壊れたドキュメント、Node のバージョンが22未満 | すべてのコマンド |
| 3 | 内部エラー。ghostchars のバグ | すべてのコマンド |
優先順位は厳密で、入力全体にわたって累積します。3は2に、2は1に、1は0に 優先します。あるファイルのデコードに失敗した場合、別のファイルに問題が 見つかっていても、終了コードは2になります。
コード3では1行が出力され、環境変数 GHOSTCHARS_DEBUG=1 が設定されている場合は、
スタックトレースも出力されます。これにより、エージェントは「間違ったフラグを
渡した」と「ツールが壊れた」を区別できます。これらは、次に取るべき対応が異なります。
標準出力での EPIPE は何も出力せずに終了コード0となるため、
ghostchars inspect big.md | head は他のコマンドと同じように動作します。
JSON 出力
clean、inspect、check で --json を指定すると、stdout に JSON オブジェクトが正確に 1 つ出力され、複数行のストリームにはなりません。機械で読み取るためのルールは 4 つあります。ok と exitCode はプロセスのステータスだけでなくペイロードにも含まれます。件数はリストより前に置かれるため、読み取りが途中で切れても判定を確認できます。上限に達した場合は必ず findingsTruncated と findingsTotal が設定されます。また、キーはキャメルケースです。
3 つのコマンドは同じ 5 つの識別フィールドから始まるため、読み取り側はほかの内容を見る前に、手元にあるものを判別できます。
{
"tool": "ghostchars",
"version": "1.0.2",
"command": "clean",
"ok": true,
"exitCode": 0
}
clean と inspect では続いて、bar、解決済みの options リスト、入力全体の合計を示す summary、そして入力ごとに 1 つのエントリーを持つ results が出力されます。clean の結果には、changed、その結果固有の summary、コードポイント単位の charsDelta、クリーニング済みの全文(-i を指定した場合は written: true に置き換え)、および rewriteSites が含まれます。inspect の結果には、clean、total、summary、種類ごとの集計である byKind、続いて line、col、index、cp、u、name、kind、flag、action を含む findings が含まれます。置換の場合のみ、さらに replacement が含まれます。
特に確認すべきフィールドは rewriteSites です。 ここには、ダッシュが空白以外の文字 2 つに挟まれている位置だけが列挙されます。これは --punct が単独のハイフンを置換する箇所です。こうした文はそのまま受け入れるのではなく、書き直す必要があります。カギ括弧、三点リーダー、ノーブレークスペースは適切に処理され、一覧には含まれません。
check の出力形式は異なります。ゲートには単一のしきい値がないためです。root、discovery、config、各サーフェス固有のしきい値、オプション、件数を持つ surfaces 配列に続いて、filesScanned、filesSkipped、filesFailing、status と hits を含む failures、さらに skippedTruncated と skippedTotal を伴う、最大 50 件の skipped リストが出力されます。
唯一の例外は report --json です。エンベロープはなく、キーはスネークケースです。 この出力は、整数値の浮動小数点数を 12.0 のように表示する方法も含め、Python 参照レポートとバイト単位で同一です。そのため、どちらの実装から出力されたペイロードも差分比較できます。結果が 1 件なら、ラップされていないレポートオブジェクトが出力されます。それ以外の場合は {label: report} マップが出力されます。この条件で数えるのはファイル引数の数ではなく、RESULTS の数です。そのため、2 つのファイルのうち 1 つを読み取れなかった場合でも、レポートはラップされずに出力されます。
エージェントへのインストール
CLI だけで十分です。シェルコマンドを実行できるエージェントなら、npx -y ghostchars check --bar text を実行できます。以下のファイルを使えば、その都度指示しなくても実行されるようになります。これらはパッケージに含まれているため、グローバルインストールの場合は $(npm root -g)/ghostchars/integrations/ から、ローカルインストールの場合は node_modules/ghostchars/integrations/ からコピーしてください。
integrations/README.md に、ツールごとのコピーコマンドが記載されています。
フック。 integrations/hooks/ は Claude Code の PostToolUse フックです。エージェントが書き込んだファイルや編集したファイルをすべてテキストバーでチェックし、指摘事項をフィードバックとして返すため、モデルは同じターン内で修正できます。ファイルを書き換えることはありません。スクリプトを .claude/hooks/ にコピーし、設定の断片を .claude/settings.json にマージしてください。
スキル。 integrations/skills/ghostchars/ は、SKILL.md と 2 つのリファレンスファイルを格納する 1 つのディレクトリです。これを .claude/skills/ghostchars/ と .agents/skills/ghostchars/ にコピーするか、一方に配置してもう一方をシンボリックリンクにしてください。これだけで、Claude Code、Codex、Cursor、Copilot を使用する VS Code、Gemini CLI に対応できます。ここにあるファイルの中で最も重要なものです。ツールを実行するタイミングと、さらに重要な点として、各種の指摘事項への対処方法をエージェントに伝えます。
常時適用されるルールブロック。 integrations/rules/ には、AGENTS.md、CLAUDE.md、GEMINI.md に貼り付ける短いブロックと、Cursor、Windsurf、Copilot 用のすぐに使えるルールファイルがあります。スキルは必要に応じて読み込まれますが、これらは常にコンテキストに含まれます。Windsurf はスキルに対応していないため、ルールファイルが唯一の連携手段となります。
MCP サーバー。 integrations/mcp/ には、ホストごとの設定スニペットが含まれています。追加すると、型付きの入出力を備えた 4 つの読み取り専用ツール(clean_text、inspect_text、style_report、check_paths)がエージェントに提供されます。構造化ツールを優先するホストでは、シェルへの往復と JSON の解析を省けます。5 つ目のツールである clean_files はディスクに書き込むため、--allow-write を指定した場合にのみ登録されます。
3 つのうち 1 つでも、すべてでも選べます。互いに競合することはありません。
Python のリファレンス CLI との違い
ゴールデンフィクスチャでは、すべてのテキストフィクスチャとすべてのオプションの組み合わせについて、clean と inspect が Python とバイト単位で一致すること、また report --json がバイト単位で完全に一致することを固定しています。以下はすべて意図的な違いであり、それぞれテストで固定されています。
| 動作 | Python | ghostchars |
|---|---|---|
長いオプションの省略形。--punct の代わりに --punc を指定 | 受け付ける | 不明なフラグとして扱い、終了コード 2 を返し、最も近い既知のフラグを表示 |
| 構文エラー時の使用方法のテキスト | argparse の折り返されたブロック | 1 行のメッセージと候補、および help --json への案内 |
| ファイルがない、または読み取れない場合 | トレースバック、終了コード 1 | {path}: no such file or directory、終了コード 2 |
| ファイルへの直接書き込み | 切り詰めて書き込む | 一時ファイルを使い、fsync を実行し、モードを複製し、シンボリックリンクを解決してからリネーム |
clean での .html と .htm | マークアップを含めてプレーンテキストとして処理 | 構造的に処理。--as text で従来の動作に戻せる |
| 認識できない拡張子 | unsupported type エラー | プレーンテキスト |
report の人間向け表示 | 中黒と en ダッシュを区切り文字に使用 | ASCII の , と to。report のバイト単位の一致は --json で実現 |
読み取れないファイルに対する report | 例外を出力し、常に終了コード 0 | メッセージを出力し、終了コード 2 |
| 内部エラー | トレースバック、終了コード 1 | 1 行のメッセージ、終了コード 3。GHOSTCHARS_DEBUG=1 の場合はスタックを表示 |
| stdout の SIGPIPE | メッセージを表示し、終了コード 120 | 何も出力せず、終了コード 0 |
--nfc または --nfkc 使用時の検出結果 | 個別のコードパスを使い、相互参照しない | clean --json は元のテキストから検出結果をスキャンするため、正規化された文字が found-not-targeted として表示される場合があります。正規化後のテキストが正となります |
| Unicode データベースに名前がないコードポイントの NAME 列 | <unnamed> | 名前がある C0 または C1 制御文字では標準エイリアス(BELL、NEXT LINE)、それ以外では U+XXXX |
最後の行は表のほかの項目とは逆です。このツールがリファレンスより多く表示する唯一の箇所であり、少なく表示することはありません。Unicode Character Database に名前があるコードポイントは、そっくりな文字も含め、すべてここでも同じ名前になります。テストでは、名前を付けられる 1508 個すべての類似文字を unicodedata と双方向に比較するため、名前の欠落も誤りも失敗になります。
Python に相当する機能がなく、新たに追加されたもの:--bar、--json、--stdin-name、--as、--limit、--fail-on、--fix、check コマンド全体、および mcp サーバー。
アトミック書き込みについて知っておくべき点が 2 つあります。実際に書き込むとファイルの inode が変わるため、そのファイルへのハードリンクは切れます。また、書き込み中にクラッシュすると、元のファイルは切り詰められず、元のファイルの隣に .ghostchars-*.tmp ファイルが残ります。変更のないファイルは書き込み用に開かれないため、更新日時と inode はそのまま維持されます。
できないこと
- SynthID-Text や KGW などの統計的ウォーターマーク。 これらは文字ではなく、単語の選択に含まれています。除去できるのは書き換えのみです。
- 文体の検出。 語彙、リズム、構造が対象です。
reportは編集できるよう、こうした特徴の一部を測定しますが、検出器ではありません。確率やスコアは出力せず、テキストが生成されたかどうかを判断することもありません。 - PDF、画像、
.pptx、.xlsx、.rtf、.doc、.epub、.pages、および Google Docs。 EXIF、XMP、C2PA には別のツールが必要です。 - テキストの周囲に隠れているものの除去。 隠しラン、コメント、変更履歴は報告されますが、削除されることはありません。
check以外でのエスケープ。 ソースファイル内でバックスラッシュ-u エスケープとして記述された U+2014 EM DASH は、ghostchars.jsonサーフェスでdecodeEscapesを有効にしない限り認識されません。また、ツールが解析しない言語から文字列リテラルを抽出する同等の機能もありません。checkまたは MCP 経由でのドキュメント処理。 リポジトリを走査するゲートは zip アーカイブを開きません。- ネットワーク経由の処理全般。 このパッケージにネットワークコードやテレメトリーはありません。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。