CLI リファレンス
zanei の全コマンド・フラグ・共通規約・終了コード。
すべての機能は単一バイナリ zanei に入っています。デーモン管理、権限診断、データ取得、フィルタ管理、agent セットアップ、MCP サーバまでこの 1 つで完結します。CLI と MCP サーバは同一コア・同一ストアの薄いラッパーであり、このページの規約を共有します。
- 署名・notarize 済みの単一 Rust バイナリ。外部ランタイム依存なし。
- 完全ローカルで動作し、CLI はいかなる外部送信も行いません。
- 破壊的操作(
purge)以外は副作用が小さく、agent から安全に呼べます。
コマンド一覧
| コマンド | 概要 |
|---|---|
doctor |
macOS 権限と recorder health の診断、権限付与の誘導 |
start |
バックグラウンド記録の開始(launchd) |
stop |
記録停止と登録解除(データは保持) |
pause / resume |
記録の一時停止 / 再開 |
status |
稼働状態・イベント件数・ストア情報 |
record |
前面での捕捉を stdout/ファイルへ(デバッグ・パイプ用) |
query |
条件付きで生イベントを取得 |
timeline |
LLM-ready・token budget 付きタイムライン |
export |
生イベントの一括ダンプ |
purge |
保存イベントの手動削除(破壊的) |
apps |
filter 選択用の app 一覧 |
filter |
capture-time 許可/不許可リストの管理 |
config |
設定の初期化・表示・パス・編集 |
mcp |
stdio MCP サーバの起動 |
setup |
agent 向け指示と MCP 連携の設定 |
グローバルオプション
すべてのサブコマンドで有効です。
| フラグ | 説明 |
|---|---|
--config <path> |
設定ファイルパスの上書き(既定 ~/.config/zanei/config.toml) |
--store <path> |
ストアパスの上書き(既定 ~/.local/state/zanei/store.sqlite) |
--json |
対応コマンドで JSON 出力を選択。詳細は出力形式を参照 |
-q, --quiet |
進捗・注意書きを抑制 |
-v, --verbose |
詳細ログを stderr へ |
--version / --help |
バージョン / ヘルプ |
環境変数
| 変数 | 説明 |
|---|---|
ZANEI_STORE_KEY_FILE=<path> |
ストアの暗号化鍵をログインキーチェーンではなくこのファイル(16 進数 64 文字)から読みます。ファイルとそのディレクトリがなければ recorder が作成します(mode 0600)。ソースからのビルド向けの開発用上書きです。ad-hoc 署名はビルドのたびに変わるため、そのままではキーチェーンのダイアログが出ます。常用向けではありません:鍵がディスク上に置かれます |
共通規約
時間表現
--since / --until が受け取る値は次のとおりです。
| 形式 | 例 | 意味 |
|---|---|---|
| 相対 | 15m 2h 1d 1w |
現在からの遡り。単位は s m h d w |
| 絶対 | 2026-08-16T09:00:00Z |
RFC3339 タイムスタンプ |
| キーワード | now |
現在時刻(主に --until 用) |
--until の既定は now。--since の既定はコマンドごとに timeline = 1h、query = 15m、export = 24h。
イベント型
--types はイベント型のカンマ区切りリストを受け取ります。末尾ワイルドカード(browser.*)が使えます。
出力形式
--format オプションを持つコマンドは次の値をサポートします。
| 値 | 対象コマンド | 説明 |
|---|---|---|
jsonl |
query・export・record |
1 行 1 イベントの生イベント(機械可読) |
json |
query・export・timeline |
単一 JSON。query と export は event array、timeline は構造化 timeline object |
md |
timeline |
LLM-ready Markdown(既定) |
table |
query |
人間可読の整形テーブル |
sqlite |
export |
範囲内のストアの平文 SQLite スナップショット。--out が必須 |
診断・状態コマンドは、これとは別の固定出力です。
| コマンド | 機械可読出力 | --json なし |
|---|---|---|
status・doctor |
グローバル --json のみ。--format は受け取らない |
固定の人間向け出力 |
終了コード
| コード | 意味 |
|---|---|
0 |
正常。バックグラウンド start も、recorder は生存しているが 20 秒待っても権限 snapshot が Pending の場合はこのコードを使います。ダイアログの表示には時間がかかる場合があり、何も表示されていなければ zanei doctor --fix を実行するよう案内します |
1 |
一般エラー。status は store_locked を含むすべての store_* state にもこのコードを使います |
2 |
使用法エラー(引数不正) |
3 |
確定した権限不足。バックグラウンド start は、起動済みの recorder が権限 snapshot で必要な TCC 権限の不足を報告した場合だけこのコードを使います。doctor も診断結果に同じコードを使います |
4 |
デーモン未起動(status・stop 等で対象がない) |
doctor
recorder health と、設定中の source・content opt-in に必要な TCC 権限(アクセシビリティ / 入力監視 / オートメーション)の付与状況を診断します。
zanei doctor # 人間可読。不足があれば付与手順と System Settings ペインを案内
zanei doctor --fix # 不足権限の設定ペインを対話的に順番に開く(付与自体はユーザー操作)
zanei doctor --json # agent 向け機械可読
| フラグ | 説明 |
|---|---|
--fix |
不足している権限の System Settings ペインを対話的に順番に開く |
--json |
機械可読出力 |
--fix は不足権限を 1 ペインずつ処理し、次のペインを開く前に Return キー入力を待ちます。
最後のペインの後には追加の待機はありません。--json --fix を併用しても対話は無効にならず、
まず JSON report を出力した後、必要権限が不足していれば同じ対話フローに入ります。
したがって、この組み合わせの stdout は JSON だけにはなりません。
- 必要権限がひとつでも欠けていれば終了コード 3。
input_monitoringが「必須」になるのはinput.*またはui.clickを捕捉する設定です。inputとuiのどちらも選択しない構成では、欠けていてもokです。
--json の出力は次のとおりです。
{
"ok": false,
"reported_by_recorder": true,
"capture_sources": ["app", "window", "ui", "input", "browser"],
"capabilities": {
"read_accessibility_tree": {
"state": "available", "required": true,
"required_for": ["window.focus", "window.title", "ui.focus", "ui.click", "ui.value", "content.snapshot"],
"detail": { "platform": "macos", "permission": "accessibility", "status": "granted", "settings_url": "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility" }
},
"observe_input": {
"state": "action_required", "required": true,
"required_for": ["input.key", "input.scroll", "clipboard.copy", "clipboard.paste", "ui.click"],
"detail": { "platform": "macos", "permission": "input_monitoring", "status": "denied", "settings_url": "x-apple.systempreferences:com.apple.preference.security?Privacy_ListenEvent" }
},
"automate_browser": {
"state": "deferred", "required": true,
"detail": { "platform": "macos", "permission": "automation", "status": "not_determined", "settings_url": "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation", "target_bundle_id": "com.google.Chrome" }
},
"automate_safari": {
"state": "deferred", "required": true,
"detail": { "platform": "macos", "permission": "automation", "status": "not_determined", "settings_url": "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation", "target_bundle_id": "com.apple.Safari" }
}
},
"store_key": { "state": "key_store", "detail": "the login Keychain (item \"Zanei store key\")" },
"health": {
"state": "degraded",
"degraded": { "chrome": "state=unavailable phase=query kind=apple_event code=-1712" },
"collector_failures": { "chrome": 3 }
}
}
capability の state は available / action_required / deferred です。内側の macOS detail がネイティブな permission 名と granted / denied / not_determined、対応する System Settings URL、必要な場合は target bundle ID を所有します。reported_by_recorder は、新鮮な recorder heartbeat 由来なら true です。heartbeat がなければ doctor 自身のプロセスから probe して false とし、人間向け出力には recorder 自身の権限を見るには起動が必要という注記を加えます。
store_key はストアの暗号化鍵の所在を報告します。state は key_store(鍵が見つかった。detail にログインキーチェーンか開発用上書き ZANEI_STORE_KEY_FILE かの所在が入る)、not_needed(ストアがない・平文・認識できない)、missing(ストアは暗号化されているが鍵がない)、mismatch(鍵でこのストアを復号できない)、key_store_locked / key_store_denied(detail にプラットフォームの案内。例:ログインキーチェーンがロックされている)、unavailable のいずれかです。detail は補足がある場合だけ含まれます。人間向け出力では権限の表の後に Store key: ... の行が加わります。ストアがロックされていても doctor は失敗せず、鍵の状態を報告し、権限は自身のプロセスから probe します。
Recorder health
health.state は store lock と永続化済み recorder status から得られる証拠だけを次のように分類します。
| 状態 | 意味 |
|---|---|
healthy |
現在の store owner と recorder status が一致し、status が running で、現在の degraded 理由がない |
degraded |
現在の store owner と running recorder status が一致し、現在の degraded 理由が 1 件以上ある |
stopped |
recorder status は読めるが、現在の owner がいない |
stale |
owner と永続化済み recorder instance は一致するが、その status は current と認められない(status.running が false) |
suspected_unavailable |
store owner はいるが、永続化済み recorder instance と一致しない |
status_unreadable |
選択した store status の存在確認・open・読み取りに失敗する |
status_missing |
選択した store が存在しない |
health object の field は次のとおりです。
| フィールド | JSON 型 | 意味 |
|---|---|---|
state |
string | 上記のいずれかの状態 |
degraded |
object<string, string> | null |
現在の component/reason map。読める証拠が現在の owner に属さない場合は空、status が missing または unreadable の場合は null |
collector_failures |
object<string, integer> | null |
collector ごとの永続化済み累積失敗数。回復しても count は reset されない。status が missing または unreadable の場合は null |
status_error |
string。通常は省略 | 選択した store の検査または status 読み取りの失敗詳細。status_unreadable の場合だけ存在する |
人間向け出力では Store key: の後に次の固定行が加わります。
| 行 | 値 |
|---|---|
COLLECTOR HEALTH |
health.state。現在の degraded entry ごとに indented component: reason 行が続く |
indented status: detail |
status_unreadable の場合だけ表示 |
COLLECTOR FAILURES none |
status を読み取れ、累積 map が空 |
COLLECTOR FAILURES - |
status が missing または unreadable |
COLLECTOR FAILURES |
累積 entry ごとに indented component: count 行が続く |
人間向けの component 名・reason・status error に含まれる制御文字は、見える escape として表示されます。recorder health は doctor の終了方針を変えません。終了コード 3 は引き続き必要権限の不足を意味し、health が degraded であるだけでは doctor は失敗しません。
人間向け出力の最終行には、必ず次の操作が表示されます。必要な権限が denied の場合は、
zanei start で recorder に権限を要求させ、ダイアログと System Settings の案内に従います。
アクセシビリティにはバンドル版が Zanei として自動追加されますが、入力監視はダイアログでの
付与が有効でも行がないことがあります。再起動後は一覧ではなく、recorder 由来の doctor の
結果を正とします。手動の + walkthrough では、バンドル実行時は Zanei.app のルート、
素のバイナリでは実行ファイルの path をコピーします。Command-Shift-G(または ~ 1 文字)で
その path を選択します。手動追加した bundle の行は定着します。設定と解除の全体は
権限ガイドを参照してください。Chrome Automation が not_determined の
場合は事前操作不要で、Zanei が初めて Chrome に問い合わせる際に macOS が確認します。
未署名または ad-hoc 署名のビルドでは、再ビルド時に付与済み権限がリセットされる旨も警告します。
start
launchd に登録し、バックグラウンド記録を開始します。 既に agent が登録されている場合は、launchd による登録解除の完了を最大 10 秒待ってから再登録します。 バックグラウンド起動では、まずデーモンが生存報告するまで最大 10 秒待ちます。その後、下記の権限確認にさらに最大 20 秒かかる場合があります。 recorder は起動時に、必要かつ未付与のアクセシビリティと入力監視を 1 回要求します。オートメーションは Chrome への初回の実 Apple Event まで要求しません。
zanei start # バックグラウンド記録を開始
zanei start --foreground # デーモン化せず前面で実行(開発・デバッグ用)
| フラグ | 説明 |
|---|---|
--foreground |
デーモン化せず前面で実行 |
recorder が生存を報告した後、バックグラウンド start は権限 snapshot が Pending の間、1 秒間隔で最大 20 秒再読み込みします。5 秒経過時点で、--quiet でなければ stderr に Waiting for the recorder's permission check... を 1 回だけ表示します。snapshot が確定した場合、必要権限がすべて granted なら通常の成功メッセージを表示し、条件を満たせば capture.text_content の opt-in を確認します。必要権限が不足していれば doctor と同じ付与手順を表示し、終了コード 3 で終了します。20 秒後も snapshot が Pending の場合に限り、recorder が macOS の権限ダイアログへの応答を待っていると案内します。ダイアログの表示には時間がかかる場合があり、何も表示されていなければ zanei doctor --fix を実行するよう案内し、recorder は生存しているため 終了コード 0 で終了します。recorder は動作を継続します。権限を付与した後、zanei stop && zanei start を実行し、zanei doctor で確認してください。--foreground も同じ recorder 起動時の要求ロジックを前面プロセスで実行します。
config.toml に capture.text_content が明示されていない場合、recorder が必要な権限をすべて granted と報告した最初の対話式バックグラウンド start は、次を確認します。
Record typed text and clipboard contents too? They stay in the local store like everything else (48-hour retention), password fields are always excluded, and Chrome Incognito text is never captured. You can change this anytime: zanei config set capture.text_content <true|false> [y/N]
bootstrap 前は、永続化された recorder の last-known 権限報告を使用します。この報告で確認しなかった場合、start は recorder を bootstrap して生存を待ち、今回の recorder 報告を確認します。この判定に CLI プロセスのローカル権限 probe は使用しません。ローカル probe は recorder ではなくターミナルの TCC identity を反映するためです。
y または Y のみが内容記録を有効にし、Enter、その他の回答、EOF、読取エラーは false を選びます。Zanei は config set と同じ経路で明示値を保存してファイルのその他の内容を維持し、Text content will be recorded. または Text content stays off. を表示します。bootstrap 後に確認した場合、y ではさらに Restarting the recorder to apply text content capture... と表示し、canonical な stop→start 経路で再起動します。false の回答は recorder の既定のオフ動作を維持するため、再起動しません。どちらの回答でもキーを書き込むため、確認は繰り返しません。
この質問に回答した直後、start は content snapshot の設定案内を次の英語どおりに表示します。content snapshot の y/N は確認しません。
Content snapshots (text shown in apps you choose) are a separate opt-in. Choose the apps first
(zanei filter content-snapshot only-app add <APP>, or exclude-app), then enable it with
zanei config set capture.content_snapshot true.
capture.text_content がすでに明示済みで質問を表示しない場合、この案内も表示しません。恒常的な入口は CONTENT SNAPSHOT status 行です。
--foreground、stdin または stderr が非 TTY、--quiet、--json、権限不足、権限状態を判定できない場合には確認しません。スキップした start は設定を未決定のままにして、従来の opt-in 案内を表示します。キーが明示的に true または false なら確認しません。
recorder は初回起動時にストアの暗号化鍵を生成し、「Zanei store key」としてログインキーチェーンに保存します。0.2.x 以前が書いた平文のストアは書き換えません。recorder はそれを store.sqlite.plaintext-<日時> に名前変更し、新しい暗号化ストアを作成します。読み取りは、旧イベントが保持期間を外れるまで新旧両方を返します(FAQ を参照)。recorder はキーチェーンのダイアログを表示しないため、ログインキーチェーンがロックされていると start は store is locked: your login Keychain is locked; unlock it (for example by opening Keychain Access) and try again で失敗します。
1 つのストアを所有できる recorder は 1 instance だけです。同じストアに対して foreground または launchd recorder を二重起動すると終了コード 1 となり、現在の owner PID を表示します。
バックグラウンド起動に成功すると、Zanei が launchd のバックグラウンド項目として 登録されたことを表示します。macOS の通知や Login Items & Extensions への表示は正常な挙動です。
stop
選択したストアを所有する recorder instance を停止します。launchd recorder は登録解除し、
foreground recorder には SIGTERM を送ります。破壊的操作ではありません。データは保持されます。
対象 recorder がなければ終了コード 4。
停止は 2 段階の bounded wait を順番に行います。まず選択した store owner の消失を最大 10 秒待ち、 launchd recorder の場合は続けて launchd 登録の除去をさらに最大 10 秒待ちます。どちらかが timeout した場合はエラーになります。
zanei stop
pause
デーモンを解除せず、記録だけを一時停止します。
zanei pause --for 30m # 30 分後に自動再開
zanei pause # resume まで無期限
| フラグ | 説明 |
|---|---|
--for <TIME> |
停止期間。省略時は resume まで無期限 |
resume
一時停止から再開します。
zanei resume
status
デーモンの状態・捕捉設定・ストア統計を表示します。
zanei status
zanei status --json
人間向け出力は、有効な TEXT CONTENT と CONTENT SNAPSHOT に現在の app/site scope を表示し、無効な行には明示的な有効化 command を表示します。例は TEXT CONTENT on (apps: exclude 6, sites: exclude 0) と CONTENT SNAPSHOT off (opt-in: zanei config set capture.content_snapshot true) です。両方の privacy-sensitive な opt-in を JSON なしで確認できます。
{
"state": "running",
"running": true,
"paused": false,
"since": "2026-08-16T08:00:00.000Z",
"instance": "4242@2026-08-16T08:00:00.000Z",
"mode": "launchd",
"uptime_s": 3600,
"events_captured": 12345,
"events_dropped": 2,
"collector_failures": { "eventtap": 1 },
"last_event_ts": "2026-08-16T08:59:58.000Z",
"heartbeat_freshness": "fresh",
"heartbeat_age_s": 2,
"last_event_age_s": 4,
"store_write_state": "healthy",
"degraded": {},
"store": { "path": "~/.local/state/zanei/store.sqlite", "size_bytes": 5242880, "retention_hours": 48, "oldest_event_ts": "2026-08-14T09:00:00.000Z", "encryption": "sqlcipher" },
"capture": { "sources": ["app", "window", "ui", "input", "browser"], "text_content": false, "content_snapshot": false },
"permissions_ok": true
}
JSON object は常に次の field を持ちます。integer は非負整数です。
| フィールド | JSON 型 | 意味と null 条件 |
|---|---|---|
state |
string | store lock に owner がいれば running、いなければ stopped。検査失敗時は store_missing / store_unavailable / store_corrupt / store_locked(ストアは暗号化されているが鍵で開けない。理由は degraded.store)。null にならない |
running |
boolean | lock owner の有無。store_* state でも null にならない |
paused |
boolean | null | store を読める場合、lock owner が存在し、その heartbeat が fresh で pause request が有効な場合だけ true。stale・future・missing heartbeat および読める stopped store は false。database 内容を読めない場合は null |
since |
string | null | 現在の owner の RFC3339 起動 timestamp。owner がなければ null |
instance |
string | null | PID と起動 timestamp からなる現在の owner identity。owner がなければ null |
mode |
"foreground" | "launchd" | null |
現在の owner の lifecycle mode。owner がなければ null |
uptime_s |
integer | null | 現在の owner の起動後秒数。owner がなければ null |
events_captured |
integer | null | 永続化済みの累積捕捉数。database 内容を読めない場合は null |
events_dropped |
integer | null | backpressure・queue full・切断等で実際に失われた配送 loss の永続化済み累計。帰属不能で記録対象外の入力と crash / SIGKILL 時の未 flush loss は含まない。database 内容を読めない場合は null |
collector_failures |
object<string, integer> | null |
collector ごとの永続化済み累積失敗数。空 object は記録済み失敗なし。database 内容を読めない場合は null |
last_event_ts |
string | null | 最新 event の RFC3339 timestamp。event がない場合、または database 内容を読めない場合は null |
heartbeat_freshness |
"fresh" | "stale" | "future" | "missing" | null |
store を読める場合、heartbeat の経過秒数の整数部が 0〜15(両端を含む)なら fresh、15 より大きければ stale、timestamp が時計より未来なら future、未記録なら missing。database 内容を読めない場合だけ null |
heartbeat_age_s |
integer | null | heartbeat の経過秒。未来 timestamp は 0 に切り上げる。heartbeat 未記録または database 内容を読めない場合は null |
last_event_age_s |
integer | null | 最新 event の経過秒。未来 timestamp は 0 に切り上げる。event がない場合または database 内容を読めない場合は null |
store_write_state |
"healthy" | "suspected_unavailable" | "heartbeat_stale" | "stopped" | null |
healthy には lock owner とそれに一致する fresh heartbeat が必要。owner なしは stopped。owner/heartbeat 不一致、または一致する非 fresh heartbeat かつそれより新しい event がない場合は suspected_unavailable。残る owner 一致・非 fresh・新しい event ありの場合は heartbeat_stale。database 内容を読めない場合は null |
degraded |
object<string, string> |
永続化済み instance が現在の owner に一致するときだけ現在の component/reason map、それ以外は空。store 検査失敗は store key で報告。null にならない |
store.path |
string | 選択した store path。null にならない |
store.size_bytes |
integer | null | file metadata を取得できる場合の byte 数。取得不能または file 不在なら null |
store.retention_hours |
integer | null | store を読める場合、owner に一致する heartbeat が fresh なら recorder の active 値、それ以外は現在の設定値。database 内容を読めない場合は null |
store.oldest_event_ts |
string | null | 保持中の最古 event timestamp。event がない場合または database 内容を読めない場合は null |
store.encryption |
"sqlcipher" | "plaintext" | null |
暗号化されたストアは sqlcipher。暗号化以前に書かれたストアは plaintext で、recorder が次回起動時に退避する。ストアがない、または読めない場合は null |
store.retired_plaintext |
string[] | 暗号化へのアップグレード時に退避した平文ストアのうち、読み取りがまだ含めているもの(古い順)。保持期間を外れると空になります。人間向け出力では PREVIOUS STORE 行として表示。読めないものはスキップし degraded.retired_store に報告します |
capture.sources |
string[] |
現在の設定の source。null にならない |
capture.text_content |
boolean | 現在の設定の text-content opt-in。null にならない |
capture.content_snapshot |
boolean | 現在の設定の frontmost-window content-snapshot opt-in。capture.sources から独立し、null にならない |
permissions_ok |
boolean | 現在の owner と instance が一致する fresh heartbeat の permission snapshot があればその値。snapshot がない場合、または heartbeat が stale・future・missing な場合はローカル probe。null にならない |
人間向け出力は --format で選ぶ table ではなく、次の固定行です。
| 行 | 値 |
|---|---|
STATE |
state |
PAUSED |
paused。null は - |
SINCE |
since。null は - |
INSTANCE |
instance。null は - |
MODE |
mode。null は - |
EVENTS CAPTURED |
events_captured。null は - |
EVENTS DROPPED |
events_dropped。null は - |
LAST EVENT |
last_event_ts。null は - |
HEARTBEAT |
freshness と、age があれば (<N>s old)。freshness が null なら - |
STORE WRITES |
store_write_state。null は - |
STORE |
store.path。store.encryption が null でなければ (encrypted) または (plaintext; the recorder encrypts it on its next start) が続く |
TEXT CONTENT |
on (apps: <exclude|only> N, sites: <exclude|only> N) または off (opt-in: zanei config set capture.text_content true) |
CONTENT SNAPSHOT |
on (apps: <exclude|only> N, sites: <exclude|only> N) または off (opt-in: zanei config set capture.content_snapshot true) |
PERMISSIONS OK |
true または false |
COLLECTOR FAILURES |
空 map は none。store を読み取れない場合は -。それ以外は各 entry の indented component: count 行が続く |
DEGRADED |
空 map は false。それ以外は true と、各 entry の indented component: reason 行 |
この human 出力表にない JSON field は human mode では表示されません。
終了コードは running が 0、stopped が 4、すべての store_* state が 1 です。
store_corrupt の場合は、破損ファイルを保持したまま新しい store を作成します。
zanei stop
mv ~/.local/state/zanei/store.sqlite ~/.local/state/zanei/store.sqlite.corrupt
zanei start
既定値以外を設定している場合は、その store path に読み替えてください。退避したファイルは調査用に残り、新しい store は空です。
鍵がない、または一致しない store_locked も同じ手順で復旧します。新しい store は既存の鍵で作成され、鍵がなければ新しい鍵を生成します。鍵を失って消えるデータは、最大でも保持期間(既定 48 時間)分です。degraded.store がログインキーチェーンのロックを示す場合は、store を退避せず、ロック解除してから再試行してください。recorder はキーチェーンのダイアログを表示しないため、キーチェーンがロックされている間は zanei start が失敗します。zanei status と zanei query は macOS のロック解除ダイアログを表示することがあります。鍵の状態は zanei doctor が報告します。
record
デーモン化せず、生イベントを NDJSON で stdout(またはファイル)へストリームします。パイプ実験・検証用です。常用の記録は start を使ってください。
zanei record --stream # NDJSON を stdout へ
zanei record --out events.jsonl # ファイルへ
| フラグ | 説明 |
|---|---|
--stream |
発生順に stdout へストリーム |
--out <FILE> |
ファイルへ書き出し |
--format jsonl |
出力形式(NDJSON) |
query
条件に合う生イベントを取り出します。構造化された機械可読出力。
zanei query --since 15m --types browser.navigate,app.activate
zanei query --since 2h --app Safari --format json --limit 500
| フラグ | 説明 |
|---|---|
--since / --until |
対象範囲(既定 --since 15m) |
--types <TYPE,...> |
イベント型フィルタ(カンマ区切り。browser.* 可) |
--app <NAME> / --bundle-id <ID> |
アプリ名 / バンドル ID で絞り込み |
--limit <N> |
最大件数(既定 500) |
--format |
jsonl(既定)/ json / table |
これらは query-time フィルタで、読み出しを絞るだけです。記録対象には影響しません(フィルタ参照)。
--types を省略すると content.* を除外します。snapshot 本文を読むときは --types content.snapshot または --types content.* を明示します。他の family と併記できます。--format json は event object の array のままです。store に未知の event type があれば skip し、件数を stderr に warning として出します。global --quiet で抑止できます。
timeline
生イベントをセッション分割・重複除去・coalesce し、token budget 内に収めた LLM 向け要約を返します。agent が最もよく呼ぶコマンドです。
zanei timeline --since 1h --format md --token-budget 4000
zanei timeline --since 30m --format json --granularity fine
| フラグ | 説明 |
|---|---|
--since / --until |
対象範囲(既定 --since 1h) |
--format |
md(既定、LLM-ready Markdown)/ json(構造化) |
--token-budget <N> |
概算トークン上限(既定 4000、下限 34)。超過分は粒度を粗くして収める |
--granularity |
coarse(既定、セッション単位)/ fine(操作単位まで) |
既定の --format md 出力の抜粋です。activity の固定句と header は次のとおり出力されます。
# Zanei timeline
Range: 2026-08-16T08:00:00.000Z — 2026-08-16T09:00:00.000Z
Estimated tokens: 3810
Truncated: no
## 2026-08-16T08:12:00.000Z — 2026-08-16T08:31:00.000Z · Safari
Title: Reviewing PR #42
- Browsed 3 pages on github.com
- Edited text in "Reviewing PR #42"
Content snapshots: 3
--format json では同じ session を range・token_estimate・truncated・skipped_unknown_types・sessions で表し、activity には同じ固定句を使います。各 JSON session は 0 を含めて content_snapshots を常に持ちます。Markdown は snapshot 件数が 0 でないときだけ activity の後に Content snapshots: N を表示し、本文は inline しません。JSON session は event_ids_truncated を
常に含み、token budget が許す場合は最大 100 件の event_ids も含みます。event_ids は
session を削除する前に省略されることがあります。
snapshot だけの範囲や最初の通常 event より前の snapshot でも、metadata に基づく空の activity・event list を持つ session を出力します。
export
範囲内の全生イベントをダンプします(バックアップ / 外部処理用)。
zanei export --since 24h --format jsonl --out dump.jsonl
zanei export --since 24h --format sqlite --out snapshot.sqlite
zanei export --since 24h --types app.*,window.*,ui.*,input.*,browser.*,clipboard.* --format sqlite --out share.sqlite
| フラグ | 説明 |
|---|---|
--since / --until |
対象範囲(既定 --since 24h) |
--types <TYPE,...> |
任意の event-type filter。jsonl / json / sqlite すべてに適用 |
--format |
jsonl / json / sqlite |
--out <FILE> |
出力ファイル。--format sqlite では必須 |
export は全形式で既定ですべての event type を含み、content.snapshot も含みます。query と異なり、--types 省略時に content を隠しません。--format json は event object の array のままです。JSON / JSONL export は未知の event type を skip し、--quiet でなければ件数を stderr に warning として出します。
--format sqlite は、稼働中のストアと同じテーブル(events・daemon_state・daemon_capabilities・meta)を持つ平文の SQLite スナップショットを、指定範囲について書き出します。保持期間は他の読み取りと同様に適用されます。SQLite export は対象 row を decode せず copy するため、未知 type も skip せず copy します。--out は必須で、省略すると使用法エラー(code 2)です。ファイルは所有者のみ読み書き可(mode 0600)で作成され、上書きはしません。既存のパスを指定すると code 1 で失敗し、snapshot file already exists at PATH; choose another --out path を表示します。成功時は Wrote a plaintext SQLite snapshot with N events to PATH を表示します(--quiet で抑制)。snapshot は暗号化されず、content.* が対象なら本文を平文で含みます。機微な JSONL export と同様に扱い、共有・外部処理に必要な family だけを --types で選んでください。sqlite3、DB Browser for SQLite、各言語の SQLite バインディング、および zanei query --store snapshot.sqlite で開けます。
purge
保持期間による自動 purge とは別に、手動で削除します。破壊的操作です。
zanei purge --before 24h # 24 時間より古いイベントを削除
zanei purge --all # 全削除(確認プロンプトあり。--quiet で抑制)
zanei purge --types '*' # これも全削除(--all と同じ確認)
zanei purge --types content.* --before 24h
zanei purge --types content.* --app Slack
zanei purge --types content.* --bundle-id com.tinyspeck.slackmacgap
| フラグ | 説明 |
|---|---|
--before <TIME> |
これより古いイベントを削除 |
--types <TYPE,...> |
一致する event type だけ削除。wildcard 可。scope のない '*' は --all と同じ確認あり |
--app <NAME> / --bundle-id <ID> |
一致する app の event だけ削除。相互排他 |
--all |
全削除(確認プロンプトあり) |
--types は --before と app selector 1 つを組み合わせられます。後から app を除外したとき、その app の snapshot だけを削除できます。scope のない --types '*' は全件選択なので、--quiet を指定しない限り --all と同じ確認が必要です。content.* のような狭い type pattern では確認しません。この削除は不可逆で dry-run はありません。command は適用 scope と削除件数を報告します。store が存在しない場合、purge は Purged 0 events を表示し、store を作成しません。暗号化への upgrade 時に退避した平文 store も対象で、scoped option は一致 row を削除し、--all は file ごと削除します。
apps
filter で選べる app を installed app・running app・store に残る app.activate event から一覧します。
zanei apps
zanei apps slack
zanei apps slack --json
任意の QUERY は name または bundle ID の大文字小文字を無視した部分一致です。table は NAME・BUNDLE ID・SOURCES(installed / running / recent)・LAST USED を表示します。recent、その他の running、installed の順です。該当なしも code 0 で、stderr に No apps match "QUERY". を表示します。TCC 権限は不要で、daemon 停止中も動きます。
--json は同じ順序で { "apps": [{ "name", "bundle_id", "path", "installed", "running", "last_used" }], "recent_unavailable": null, "installed_unreadable": 0 } を返します。store が不在または開けない場合も installed / running app は残り、recent_unavailable に理由が入ります。Info.plist がない、読めない、または不正な app bundle は読み飛ばし、その件数を installed_unreadable に返します。0 より大きい場合は stderr に warning: N app bundles could not be read も表示します。
filter
3 つの capture-time scope を管理します:全 event の [filter]、入力・clipboard 本文の [filter.text_content]、snapshot event の [filter.content_snapshot]。コマンドの形は zanei filter [<scope>] <list> add|remove [VALUE] で、<scope> は省略・text-content・content-snapshot のいずれかです。
zanei filter show
zanei filter exclude-app add 1Password
zanei filter text-content exclude-app add Slack
zanei filter content-snapshot only-app add Terminal
zanei filter content-snapshot exclude-site add mail.google.com
zanei filter content-snapshot exclude-app add FutureApp --unverified
| list | config suffix | 意味 |
|---|---|---|
exclude-app |
exclude_apps |
指定 app を除外。exclude / only mode の両方で有効 |
only-app |
include_only_apps |
非空なら指定 app だけを含める |
exclude-site |
exclude_websites |
指定 Chrome/Safari URL host を除外。両 mode で有効 |
only-site |
include_only_websites |
非空なら指定 Chrome/Safari URL host だけを含める |
- 全 app list の
addは表示名または bundle ID を受け付け、zanei appsの候補に対して解決し、bundle ID があればそれを保存します。未解決値は保存せず code 2 で終了し、近い候補があれば提示します。--unverifiedは未解決値を warning 付きで明示保存します。 - 値なしの
addは recent 順の番号選択を開きます。非 TTY または--quietでは値が必須で、省略すると code 2 です。removeは現在の list 内で解決するため、uninstall 済み entry も消せます。 filter showは 3 scope、apps/sites の mode と件数、解決した表示名、未解決 entry の(not installed)を表示します。hard-coded の組み込み除外も別に表示します。- 両 content scope は Safari・Firefox・Brave・Edge・Vivaldi・Arc を既定で除外します。
only-appに追加するとき、またはexclude-appから外すときは、private-window 判定がないため--quiet未指定なら warning を表示します。既定値は編集できます。 - サイトルールはChromeとSafariに適用します。変更は次の設定監視 cycle(通常 2 秒以内)で反映され、再起動は不要です。
評価順と各 scope が除外する field はフィルタガイドを参照してください。
config
zanei config init # 全設定項目にコメントを付けたテンプレートを生成
zanei config path # 設定ファイルのパスを表示
zanei config show # 有効設定(既定値マージ後)を表示
zanei config edit # $EDITOR で設定を開く
zanei config set capture.text_content true
zanei config set capture.content_snapshot true
config init は、対応する全設定項目と現在の既定値を含むコメント付きテンプレートを
生成します。既定の生成先は ~/.config/zanei/config.toml で、グローバル
--config <path> で別の生成先を指定できます。親ディレクトリがなければ作成します。
成功時は生成したパスを表示して終了コード 0 で終了します。生成先にファイルが存在する
場合は変更せず、既存ファイルのパスを表示して終了コード 1 で終了します。
config set <DOTTED_KEY> <VALUE> は、スカラー設定を 1 項目検証して保存します。対応するキーと値は次のとおりです。
| キー | 設定できる値 |
|---|---|
capture.text_content |
true、false |
capture.content_snapshot |
true、false |
output.batch_interval_s |
0 より大きい符号なし整数 |
output.retention_hours |
0 より大きい符号なし整数 |
配列設定には対応しません。filter リストには zanei filter、その他の配列には
zanei config edit を使います。不明なキー、配列キー、不正な値は保存せず終了コード 2 で
終了します。output.retention_hours は稼働中デーモンが再読込し、即時 retention purge に
反映します。記録デーモンの稼働中に capture.text_content・capture.content_snapshot または
output.batch_interval_s の変更に成功すると、次のメッセージを表示します。
Restart recording with `zanei stop && zanei start` for this to take effect.
config set capture.content_snapshot true は、先に現在の app/site scope を表示し、既定 N の [y/N] を待ちます。有効な list に応じて summary を作り、削除までの時間には読み込んだ output.retention_hours を使います。既定値では次の英語を表示します。
Content snapshots record the text shown in the frontmost window, including messages and
documents written by other people and text you typed that is on screen. Password fields and
Chrome Incognito windows are never captured; stored text is redacted and deleted after 48 hours.
Current scope (change it first if this is not what you want):
Apps: every app except 6 excluded (Safari, Firefox, Brave, Edge, Vivaldi, Arc)
Sites: every site
zanei filter content-snapshot only-app add <APP> record only these apps
zanei filter content-snapshot exclude-app add <APP> everything except these
zanei apps list apps to choose from
Enable content snapshots with this scope? [y/N]
N・Enter・EOF は file を変更しません。非 TTY で書き込むには --quiet が必須で、未指定なら scope summary を stderr に出し、保存せず code 2 で終了します。agent は filter content-snapshot で scope を先に決め、何を記録するかを明言してから zanei config set capture.content_snapshot true --quiet を使い、再起動します。false への変更は確認しません。
スキーマは設定リファレンスを参照。
mcp
stdio MCP サーバを起動します。stdin/stdout 上の JSON-RPC で、ネットワークは一切使いません。通常は MCP クライアント(Claude Code・Codex・opencode・Claude Desktop 等)から起動され、手で叩くものではありません。
zanei mcp [--store <PATH>]
- ストアへのread-only ビュー。記録デーモンとは独立プロセス。
- 公開ツール:
get_timeline/query_events/get_status— MCP リファレンス参照。
setup
対象 agent 向けの Zanei 指示と MCP 連携を設定します。CLI を実行する agent には skill ファイルを配置します。Claude Desktop の chat は MCP 登録のみ、opencode の MCP JSON は手動設定用に表示します。
zanei setup --agent claude # SKILL.md を Claude Code の skill 位置へ + MCP 登録
zanei setup --agent codex --scope user
zanei setup --agent hermes # skill を ~/.hermes/skills/ へ + ~/.hermes/config.yaml に MCP 登録
zanei setup --agent pi # skill を ~/.pi/agent/skills/ または .pi/skills/ へ。MCP なし
zanei setup --agent claude-desktop # claude_desktop_config.json へ MCP 登録
zanei setup --agent opencode # skill を opencode の skill 位置へ + MCP JSON を表示
| フラグ | 説明 |
|---|---|
--agent |
claude / codex / opencode / hermes / pi / claude-desktop |
--scope |
project(既定。カレントリポジトリ)/ user(ユーザー全体) |
--print |
書き込み予定のファイル変更を、実際には書き込まず表示する |
agent 別の挙動とセットアップ出力は agent セットアップを参照。