Skip to content

igapyon/miku-grep

Repository files navigation

miku-grep

miku-grep は、生成AI agent と automation が repository やディレクトリ内で「読むべきファイル」を見つけるための local-first 検索 CLI です。

通常の grep の代わりに、検索結果、summary、diagnostics を JSON として返します。人間が画面で読む検索結果ではなく、次の処理に渡しやすい structured result を得るための tool です。

厳格な CLI / JSON 仕様は docs/miku-grep-cli-spec.md を参照してください。

セキュリティに関する調査結果と対策は docs/miku-grep-security.md を参照してください。

何に使うか

miku-grep は、生成AI agent や script が local repository を読む前に、候補 file を絞り込むために使います。

主な用途:

  • file content から読むべき file を探す
  • file path から候補を探す
  • directory path から候補を探す
  • file path、directory path、content を組み合わせて探す
  • result JSON の summarydiagnostics を見て、検索範囲や skipped file を判断する
  • summary で候補 file を絞ってから、必要に応じて detail で snippet を読む

miku-grep は semantic search ではありません。embedding search や意味による ranking は行いません。

AI agent が「探す」「候補を絞る」「次に読む file を選ぶ」流れをより自然に扱えるよう、case-insensitive search、file inventory、agent summary、readfile hints、repo root 補助、glob query、encoding preset、簡易 ranking を備えています。現時点ではユーザー数が少ないため、下方互換性よりも agent が扱いやすい request / result shape を優先して設計する方針です。

すぐ使う

stdin で request JSON を渡し、stdout から result JSON を受け取ります。

miku-grep < request.json > result.json

最小 request 例:

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "search": {
    "targets": ["content"]
  }
}

root が相対 path の場合、CLI process の current working directory から解決されます。既定では指定された root だけを検索します。

subdirectory から実行して repository 全体を検索したい場合は detectGitRoot: true を指定します。result の effectiveRequest.requestedRoot には指定された root、effectiveRequest.root には実際に使った root が返ります。

--version--help は stdin JSON なしで実行できます。

miku-grep --version
miku-grep --help

--help は、生成AI agent や automation が request JSON を組み立てるために必要な stdin / stdout contract、request field、default、result shape、diagnostics、例を stdout に出力します。

よく使う request

file content を検索する

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "diagnostics"
  },
  "search": {
    "targets": ["content"]
  }
}

file path を検索する

filepathroot からの相対 file path を検索します。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "security"
  },
  "search": {
    "targets": ["filepath"]
  }
}

directory path を検索する

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "docs"
  },
  "search": {
    "targets": ["directory"]
  }
}

find のように file path と directory path を検索する

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "test"
  },
  "search": {
    "targets": ["filepath", "directory"]
  }
}

file path と content の両方を検索する

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "encoding"
  },
  "search": {
    "targets": ["filepath", "content"]
  }
}

対象 file を絞る

include / exclude は glob pattern です。query.type: "regex" は検索語の解釈だけを切り替えます。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "effectiveRequest"
  },
  "search": {
    "targets": ["content"],
    "includeFileNamePatterns": ["*.ts", "*.md"],
    "excludeDirNamePatterns": [".git", "node_modules", "dist"]
  }
}

excludeFileNamePatternsexcludeDirNamePatterns が未指定の場合は default exclude preset が使われます。.gitnode_modulestargetbuilddistvendor など、通常の検索で読みたくない directory は既定で除外されます。

.gitignore.ignore.git/info/exclude は既定で尊重されます。ignore file を無効にして検索したい場合は ignore.mode: "none" を指定します。

注意: ignore file 対応は Git ignore の subset です。!pattern による negation / unignore は対応していますが、escaped leading # / !、character class、brace expansion など一部の pattern は未対応で、該当 pattern は unsupported_ignore_pattern warning diagnostic として報告されます。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "search": {
    "targets": ["content"]
  },
  "ignore": {
    "mode": "none"
  }
}

detail 出力にする

output 未指定時は summary です。まず候補 file を絞る用途ではこれが既定です。

hit ごとの行、column、matched text が必要な場合は detail を指定します。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "search": {
    "targets": ["content"]
  },
  "output": {
    "mode": "detail",
    "maxMatches": 200,
    "maxMatchesPerFile": 20,
    "maxLineLength": 240
  }
}

match 前後の行も一緒に読みたい場合は、detail mode で context lines を指定します。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "search": {
    "targets": ["content"]
  },
  "output": {
    "mode": "detail",
    "contextLinesBefore": 2,
    "contextLinesAfter": 2
  }
}

output.contextLines を使うと、前後に同じ行数を指定できます。context lines は content hit の contextBefore / contextAfter として返り、summary mode には載せません。

Shift_JIS file を検索する

encoding auto detect は行いません。UTF-8 以外を読む場合は encoding rule を指定します。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "検索語"
  },
  "search": {
    "targets": ["content"],
    "includeFileNamePatterns": ["*.txt"]
  },
  "encoding": {
    "default": "utf-8",
    "rules": [
      {
        "fileNamePattern": "*.txt",
        "encoding": "shift_jis"
      }
    ],
    "onDecodeError": "skip"
  }
}

読めなかった file、binary と判定された file、size limit を超えた file などは diagnostics に返されます。

regex で検索する

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "regex",
    "text": "Repository(Map|Index)"
  },
  "search": {
    "targets": ["content"]
  }
}

検索は default では case-sensitive です。大文字小文字を区別せずに検索したい場合は query.case: "insensitive" を指定します。

case-insensitive 検索

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "repositorymap",
    "case": "insensitive"
  },
  "search": {
    "targets": ["content"]
  }
}

ファイル一覧モード

rg --files 相当の file inventory を JSON で返す入口です。

{
  "version": 1,
  "root": ".",
  "mode": "listFiles"
}

期待する情報:

  • .gitignore や exclude rule を反映した file path 一覧
  • extension / directory / file count summary
  • skipped path や unsupported ignore pattern の diagnostics

listFiles mode では matches[] は空配列になり、file inventory は files[]、集計は fileSummary に返ります。

agent 向け summary mode

大量の match から次に読む candidate を選びやすくする mode です。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "output": {
    "mode": "agent"
  }
}

path、target kind、match count、representative snippets、推奨 read range を返します。

agent mode の matches[]agentFile / agentDirectory item を返します。agentFilerepresentativeSnippetsreadRanges を含みます。

miku-readfile request hint

検索結果から miku-readfile に渡す request を作りやすくする handoff hint です。

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "output": {
    "includeReadfileRequestHints": true
  }
}

readfileHints[] は matched file ごとに返ります。directory match だけの結果には readfile hint は付きません。

repo root 補助

{
  "version": 1,
  "root": ".",
  "detectGitRoot": true,
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  }
}

path glob query

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "glob",
    "text": "**/*.md"
  },
  "search": {
    "targets": ["filepath"]
  }
}

query.type: "glob" は root-relative path に対する検索です。filepath / directory target と listFiles mode の絞り込みで使えます。content target との組み合わせは validation error です。

encoding preset

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "検索語"
  },
  "encoding": {
    "preset": "japanese-legacy"
  }
}

japanese-legacy preset は、よくある日本語 legacy text file pattern に Shift_JIS を適用します。明示 encoding.rules は preset より優先され、result の encodingRule には preset 由来かどうかが返ります。

簡易 ranking

{
  "version": 1,
  "root": ".",
  "query": {
    "type": "literal",
    "text": "RepositoryMap"
  },
  "output": {
    "sort": "relevance"
  }
}

output.sort: "relevance" は semantic ranking ではなく、deterministic heuristic です。summary / agent mode の候補を README / docs / src / test / match count / path match / generated らしさなどで並べ替え、各 item に relevance.scorerelevance.reasons を返します。default は再現性を優先して path です。

result の読み方

stdout の result JSON は、成功時も期待可能な失敗時も同じ top-level shape を保ちます。

{
  "version": 1,
  "ok": true,
  "error": null,
  "effectiveRequest": {},
  "matches": [],
  "summary": {
    "filesVisited": 0,
    "directoriesVisited": 0,
    "filesScanned": 0,
    "directoriesScanned": 0,
    "filesMatched": 0,
    "directoriesMatched": 0,
    "filesIgnored": 0,
    "directoriesIgnored": 0,
    "matches": 0,
    "diagnostics": 0,
    "truncated": false,
    "truncatedReason": null
  },
  "diagnostics": []
}

主な field:

  • ok: request が実行できたかどうか
  • error: ok: false のときの代表 error
  • effectiveRequest: default 適用後の実際の検索条件
  • matches: 検索結果。output.mode によって item shape が変わります
  • files: mode: "listFiles" の file path 一覧
  • fileSummary: mode: "listFiles" の extension / directory summary
  • readfileHints: output.includeReadfileRequestHints: true のときの miku-readfile handoff request
  • summary: scanned file 数、hit 数、truncation の有無
  • diagnostics: skipped file、decode error、limit 到達、validation error など

summary mode の matches[] は、matched file / matched directory を item として返します。agent が次に読む file や見るべき directory を選ぶ最初の検索に向いています。

detail mode の matches[] は、content target では 1 content hit = 1 item です。filepath / directory target では 1 matched path = 最大 1 item で、同じ path 文字列内に複数 match がある場合は代表 matchedText を返します。line、column、matched text、snippet を見たい場合に使います。

注意点

  • stdout は result JSON 専用です。progress log や runtime-level message は stderr に出します。
  • request JSON と result JSON はどちらも top-level に version: 1 を持ちます。
  • request JSON の未知 field は validation error です。
  • result JSON 内の fileroot からの相対 path です。絶対 path は返しません。
  • path separator は platform に関わらず / です。
  • symlink は MVP では追跡しません。
  • content 検索では file size、line length、match count などの resource limit が適用されます。
  • regex は Node.js RegExp を使いますが、JavaScript 固有の flags は request schema では受け取りません。

詳細な default、limit、schema、exit code、diagnostic code、sort order は miku-grep CLI Specification を参照してください。

開発

依存関係を入れます。

npm install

テストを実行します。

npm test

TypeScript compile、テスト、単一ファイル CLI bundle 生成をまとめて実行します。

npm run build

開発用 CLI の stdin / stdout smoke example を実行します。

npm run smoke

bundle 生成後に、単一ファイル runtime artifact の smoke test を実行します。

npm run smoke:bundle

主な生成物:

  • dist/main.js
  • bundle/miku-grep.mjs
  • bundle/miku-grep-sources.tgz

dist/main.js は package bin が指す開発・npm package 用 CLI entry です。

bundle/miku-grep.mjs は source tree なしで実行できる単一ファイル runtime artifact です。

bundle/miku-grep-sources.tgz は再ビルド、監査、下流確認用の source archive です。

関連ドキュメント

関連プロジェクト

後続候補

MCP adapter は当面対応しません。まずは CLI、Java 版、Agent Skills 版を通常の利用経路として扱います。