azkhh/drift
この mod について
drift
作業を進めているのか、暗闇に隠れているのかを知らせる Claude Code mod。
Claude Code の mod イベントを通してセッションを監視し、2 つのことを数えます。実際に出荷したもの(コミット、プッシュ、デプロイ、成功したテスト実行)と、整えただけのもの(ツール、設定、ドキュメント、計画への編集)です。前に進んでいる間は何も表示しません。長いあいだ何も出荷していない、最近の編集の大半が設定やドキュメントに向いている、同じファイルを書き直し続けている。このどれかに当たると、プロンプトの上に簡潔な1行を1度だけ表示します。
モデルのトークンは使わず、ネットワーク通信もプロセス実行もファイル読み取りも行いません。ツール呼び出しを数え、合計をマシン上の mod 専用ストアに保存します。
src/app.ts は出荷なしで 4 回編集されています。直近 20 回の編集のうち 12 回は設定とドキュメントでした。
Claude Code 2.1.287 以降が必要です(このバージョンから mod はデフォルトで有効です)。
インストール
claude plugin marketplace add azkhh/drift
claude plugin install drift@drift
Claude Code の中から /plugin を実行し、マーケットプレイス azkhh/drift を追加して drift をインストールすることもできます。セッションを再起動してから /drift を実行します。
インストールせず、クローンから試す場合:
claude --plugin-dir ./drift
バンドが知らせること
次のどれかを超えるまでは何も言いません。それぞれの条件を超えたときに1度だけ知らせ、その条件の値が下がるまで黙ります(出荷すると1つ目と3つ目がリセットされます)。
| しきい値 | 行 |
| --- | --- |
| 何かを出荷してからのアクティブ時間が 45 分 | 何かを出荷してから 52 分経過しています。 |
| 直近 20 回の編集の 60% 以上(少なくとも 10 回)が暗闇向け | 直近 20 回の編集のうち 14 回は設定とドキュメントでした。 |
| 同じファイルを、出荷なしで 4 回編集 | src/app.ts は出荷なしで 4 回編集されています。 |
この行は次のプロンプトを送るか、何かが出荷されるまでプロンプトの上に残ります。出荷とは、コミット、プッシュ、デプロイ、または終了コード 0 のテスト実行です。
アクティブ時間に数えるのは、イベント間の間隔が 10 分以内の場合だけです。昼食に出かければアイドルであり、drift ではありません。
/drift
| コマンド | 動作 |
| --- | --- |
| /drift | 今日の記録と直近 7 日間を表示します。アクティブ時間、出荷数、暗闇にいた時間、変更が集中したファイル、失敗した試行、目標とその継続時間です。モデルのターンは発生しません。 |
| /drift goal <text> | このプロジェクトに1つの目標を設定します(リポジトリルートをキーにします)。その後に編集したパスやコミットメッセージに、目標と意味のある共通語があるかを記録で示します。 |
| /drift goal | 目標を表示します。/drift goal clear で削除します。 |
| /drift off、/drift on | このプロジェクトのカウントを停止または再開します。 |
| /drift reset | このプロジェクトのカウンターと履歴を消去します。目標とオン/オフ状態は残ります。 |
作業と暗闇
編集したパスが次の glob のいずれかに一致すると、その編集は「暗闇」に入ります(大文字と小文字は区別せず、スラッシュのないパターンは任意の深さのファイル名に一致します)。それ以外が作業です。
CLAUDE.md AGENTS.md **/.claude/**
*.config.* package.json tsconfig* **/.github/**
.* **/.*/** (ドットファイルとドットフォルダー)
docs/**/*.md **/docs/**/*.md plan.md notes.md todo.md roadmap.md readme.md
*.lock *.lockb package-lock.json pnpm-lock.yaml go.sum
一覧は hooks/paths.ts の1か所にあります。置き換えるには、プラグインオプション Dark patterns(/plugin configure drift@drift、または /config のこのプラグインの行)を、カンマ区切りの glob 一覧に設定します。インストール時には、1つのオプションがまだ設定されていないという注記が表示されます。これは任意です。空でない値は組み込み一覧を置き換え、追加はしません。
mod イベントが見えるもの、見えないもの
この mod は Claude Code 2.1.287 の宣言を基に作られています。各部分が依存するものは次のとおりです。
編集。 Edit、Write、MultiEdit、NotebookEdit のツール呼び出しにはパスが含まれます。呼び出しが実際に適用された場合だけ編集として数えます。失敗した呼び出し(isError)や拒否された呼び出し(deny)は数えません。
出荷。 Bash ツール呼び出しにはコマンド文字列が含まれ、mod はそこから git commit、git push、vercel deploy、wrangler deploy、npm publish、fly deploy、netlify deploy、さらに npm test、pnpm test、yarn test、bun test、pytest、go test、cargo test、vitest、jest を読み取ります。ドライランは無視します。複合コマンドは引用符の中を除き、&&、||、;、| で分割します。
終了ステータス。 2.1.287 の Bash ツール結果には数値の終了コードがありません。フィールドは stdout、stderr、interrupted、backgroundTaskId などです。hook が見られるのは isError で、ツールがエラーを報告したときエンジンが設定し、ゼロ以外の終了も同じ扱いになります。実行中、T=1 npm test(終了 1)は isError: true として届き、失敗した試行に数えられました。同じコマンドの終了 0 は成功したテスト実行に数えられました。つまり mod が知るのはゼロかゼロ以外かだけです。バックグラウンドに送ったコマンドは未完了なので出荷には数えません。
捕捉できないもの。
- 1つのチェーンには終了ステータスが1つだけあります。
git commit -m x && git pushが 0 で終われば両方が実行されました。a; bとa || bは片方が失敗しても 0 で終わることがあり、npm test | tailはtailのステータスで終了するため、別のコマンドにパイプした失敗テストも成功として数えられます。 Bashで行った編集(sed -i、echo >> file、フォーマッター)は mod の編集ではありません。編集ツールだけが対象です。- 認識しない出荷は、リリーススクリプト(
npm run release)、CI からのデプロイ、別のターミナルで行ったコミットです。 - 考えたり入力したりした時間は見えません。アクティブ時間は、ツール呼び出し、プロンプト、完了したターンの間隔のうち 10 分以下のものを合計した時間です。
- 成功したテスト実行は、前進している証拠なので出荷として数えます。コミットと同じく、出荷からの時計をリセットします。
近似。「暗闇にいた時間」とは、終了イベントが暗いファイルの編集だったアクティブ時間です。時間枠内に少なくとも 10 回の編集がないと暗闇の割合は表示されないため、設定を3回続けて編集しただけでは判定しません。8 時間を超える休止で新しい実行が始まり、昨日の編集は今日に持ち越されません。目標の一致は共通語を1つ使います(小文字化し、複数形をまとめ、一般的な語とファイル拡張子を無視します)。意図は読めず、触ったものに目標への言及がないことだけを伝えます。
プライバシー
claude plugin validate はモジュールが行うすべての呼び出しを列挙します。時計、セッションのルートとリポジトリ、mod 自身の状態とストア、コマンド登録です。$.http、$.process、$.fs、$.model は呼び出しません。プロジェクトごとに目標と、直近 30 日分の日ごとの少数のカウント、変更が集中したファイル名を保存します。ファイルパスはプロジェクトルートからの相対パスで保存します。ストアは Claude Code のプラグインストアフォルダーにある JSON ファイルです。どこにも送信しません。
開発
claude plugin test . # 65 テスト、エンジン自身のホストで実行
claude plugin validate .claude-plugin/plugin.json
claude --plugin-dir . # ライブで試す。フォルダーは監視され、ホットリロードされます
Claude Code はプラグインフォルダーを読み込むたびに、型宣言を .claude-plugin/types/ に書き込みます。このフォルダーは git ignore されています。npx -p typescript tsc -p tsconfig.json はその宣言に対して hook とテストの型をチェックします。
コードは各部分を個別にテストできるよう分割されています。
| ファイル | 内容 |
| --- | --- |
| hooks/paths.ts | 暗闇の一覧、glob、オプション |
| hooks/ships.ts | コマンドラインからコミット、プッシュ、デプロイ、テスト実行を見つける処理 |
| hooks/goal.ts | 目標と共通語チェック |
| hooks/tracker.ts | アクティブ時間、編集ウィンドウ、変更集中、出荷、日別集計、3 つのしきい値 |
| hooks/receipt.ts | /drift が表示するテキスト |
| hooks/mover-line.ts | /drift を終える1行 |
| hooks/register.ts | hook:tool.call、prompt.submit、turn.complete、session.start、session.end、AbovePrompt バンド、command.run |
各 hook は一定量の処理だけを行い、ディスクを走査しません。スクリプト実行時のエンジンのデバッグログでは、編集の tool.call hook は編集自体を含めて 6~15 ms で安定して完了しました。
ライセンス
MIT、LICENSE を参照してください。
drift は編集だけを見ます。mover は、あなたがやると言ったことを覚え、実際にやったことと照合します:moveros.dev
インストール
まず作者の README で marketplace とプラグイン名を確認してください。コマンドはリポジトリの構成によって変わる場合があります。
claude plugin marketplace add azkhh/drift claude plugin install drift
原文 / README
drift
A Claude Code mod that tells you whether you are moving or hiding in the dark.
It watches a session through Claude Code's mod events and counts two things: what shipped (commits, pushes, deploys, passing test runs) and what you only tidied (edits to tooling, config, docs and plans). It is silent while you are moving. When you have gone a long stretch with nothing shipped, or most of your recent edits went to config and docs, or you keep rewriting one file, one plain line appears above the prompt. Once.
It uses no model tokens, makes no network calls, runs no processes and reads no files. It counts tool calls and keeps the totals in the mod's own store on your machine.
src/app.ts has been edited 4 times with nothing shipped. 12 of your last 20 edits were config and docs.
Needs Claude Code 2.1.287 or later (mods are on by default from that version).
Install
claude plugin marketplace add azkhh/drift
claude plugin install drift@drift
Or from inside Claude Code: /plugin, add the marketplace azkhh/drift, install drift. Restart the session, then run /drift.
To try it from a clone without installing:
claude --plugin-dir ./drift
What the band says
Nothing, until one of these is crossed. Each one speaks once per crossing, then stays quiet until the thing it measures drops back (a ship resets the first and third).
| Threshold | Line |
| --- | --- |
| 45 active minutes since anything shipped | 52 min since anything shipped. |
| 60% or more of your last 20 edits (at least 10 edits) went to the dark | 14 of your last 20 edits were config and docs. |
| The same file edited 4 times with nothing shipped between | src/app.ts has been edited 4 times with nothing shipped. |
The line stays above the prompt until you send your next prompt, or until something ships. A ship is a commit, push, deploy or test run that exited 0.
Active time counts only the gaps between events that are 10 minutes or shorter. Go for lunch and it is idle, not drift.
/drift
| Command | What it does |
| --- | --- |
| /drift | Today's receipt and the last 7 days: active time, shipped count, time in the dark, churn files, failed tries, the goal and how long it has stood. No model turn. |
| /drift goal <text> | Sets one goal for this project (keyed by the repository root). The receipt says whether any edited path or commit message since then shares a meaningful word with it. |
| /drift goal | Shows the goal. /drift goal clear removes it. |
| /drift off, /drift on | Stop or resume counting in this project. |
| /drift reset | Clears this project's counters and history. Keeps the goal and the on/off switch. |
The work and the dark
An edit is "in the dark" when its path matches one of these globs (case does not matter, a pattern with no slash matches a file name at any depth). Everything else is the work.
CLAUDE.md AGENTS.md **/.claude/**
*.config.* package.json tsconfig* **/.github/**
.* **/.*/** (dotfiles and dot folders)
docs/**/*.md **/docs/**/*.md plan.md notes.md todo.md roadmap.md readme.md
*.lock *.lockb package-lock.json pnpm-lock.yaml go.sum
The list lives in one place, hooks/paths.ts. To replace it, set the plugin option Dark patterns (/plugin configure drift@drift, or the row for this plugin in /config) to a comma separated list of globs. The install prints a note that one option is not set yet; it is optional. A non empty value replaces the built in list, it does not add to it.
What the mod events can and cannot see
The mod is built against the Claude Code 2.1.287 declarations. Here is what each part rests on.
Edits. Edit, Write, MultiEdit and NotebookEdit tool calls carry the path. An edit counts only if the call landed: a call that failed (isError) or was refused (deny) counts for nothing.
Ships. Bash tool calls carry the command text, which the mod reads for git commit, git push, vercel deploy, wrangler deploy, npm publish, fly deploy, netlify deploy, and npm test, pnpm test, yarn test, bun test, pytest, go test, cargo test, vitest and jest. Dry runs are ignored. Compound commands are split at &&, ||, ; and |, never inside quotes.
Exit status. The Bash tool result in 2.1.287 has no numeric exit code. Its fields are stdout, stderr, interrupted, backgroundTaskId and a few more. What the hook does see is isError, which the engine sets when the tool reported an error, and a non zero exit is one. In a live run, T=1 npm test (exit 1) arrived as isError: true and was counted as a failed try, and the same command with exit 0 counted as a passing test run. So the mod knows zero from not zero, and nothing finer. A command sent to the background has not finished and is not counted as shipped.
What that does not catch.
- A chain has one exit status.
git commit -m x && git pushexiting 0 means both ran.a; banda || bcan exit 0 with one part failed, andnpm test | tailexits withtail's status, so a failing test run piped through another command counts as a pass. - Edits made through
Bash(sed -i,echo >> file, a formatter) are not edits to the mod. Only the edit tools are. - Ships it does not recognise: a release script (
npm run release), a deploy from CI, a commit you make in another terminal. - It does not see time spent thinking or typing. Active time is the sum of gaps of 10 minutes or less between tool calls, prompts and finished turns.
- A passing test run counts as a ship, because it is evidence of moving. It resets the clock since a ship like a commit does.
Approximations. "Time in the dark" is the active time whose closing event was an edit to a dark file. The dark share needs at least 10 edits in the window before it can speak, so three config edits in a row are not a verdict. A break of more than 8 hours starts a fresh run, so yesterday's edits do not count against today. The goal match is one shared word (lowercased, plurals folded, common words and file extensions ignored); it cannot read intent, it can only tell you that nothing you touched has mentioned the goal.
Privacy
claude plugin validate lists every call the module makes: the clock, the session's root and repository, the mod's own state and store, and the command registration. It makes no $.http, $.process, $.fs or $.model call. Per project it stores the goal and, for the last 30 days, a few counts per day and the names of the files that churned. File paths are stored relative to the project root. The store is a JSON file in Claude Code's plugin store folder. Nothing is sent anywhere.
Development
claude plugin test . # 65 tests, run by the engine's own host
claude plugin validate .claude-plugin/plugin.json
claude --plugin-dir . # try it live; the folder is watched and hot reloads
Claude Code writes its type declarations to .claude-plugin/types/ every time it loads a plugin folder; that folder is git ignored. npx -p typescript tsc -p tsconfig.json type checks the hooks and tests against it.
The code is split so each piece can be tested on its own:
| File | What it holds |
| --- | --- |
| hooks/paths.ts | The dark list, the globs, the option |
| hooks/ships.ts | Finding commits, pushes, deploys and test runs in a command line |
| hooks/goal.ts | The goal and its shared word check |
| hooks/tracker.ts | Active time, the edit window, churn, ships, day totals, the three thresholds |
| hooks/receipt.ts | The text /drift prints |
| hooks/mover-line.ts | The one line that ends /drift |
| hooks/register.ts | The hooks: tool.call, prompt.submit, turn.complete, session.start, session.end, the AbovePrompt band, command.run |
Every hook does a constant amount of work and no disk scan. In a scripted run the engine's debug log showed the tool.call hook settling in 6 to 15 ms for an edit, with the edit itself included in that time.
License
MIT, see LICENSE.
drift only sees your edits. mover remembers what you said you'd do and checks it against what you did: moveros.dev
