Go agent — NAS 同期エージェント
agent/ は顧客の NAS・PC 上で常駐する Go 製バイナリ(astar-agent)です。ファイルをクラウドにコピーせず、Astar の Web UI から閲覧・検索・AI 抽出できるようにするのが目的です。ファイル本体は顧客のストレージに置かれたまま、agent がメタデータ(と要求時のみコンテンツ)を backend に流します。
動き方の要点
- agent は backend にアウトバウンドの WSS 接続を張る(backend が agent にダイヤルインすることはない)。認証は WS 接続メッセージ内で行う in-band 方式で、HTTP ヘッダ認証ではない。
- 監視対象ディレクトリ(root)をスキャン・監視し、ファイルの追加・変更・削除を検知してイベントを backend に送る。
- backend からのコマンド(ファイル読み取り・書き込み・削除・検索)を WebSocket 経由で受け取り、ローカルファイルシステムに対して実行する。
実パッケージ一覧
ls agent/cmd/ ls agent/internal/ で確認できる実際の構成です。存在しないパッケージ名(repositories/・pkg/・internal/handler)を前提にしないでください。
agent/cmd/ — 補助バイナリ
| パッケージ | 役割 |
|---|---|
fakecli | ローカル/dev テスト用の偽 CLI プロバイダ。claude -p の stream-json 出力を再現する |
generate-messages | go:generate codegen。asyncapi.yaml から Go の struct を生成する |
mcpbridge | astar-agent mcp-bridge サブコマンドの実体。Claude Code が agent を stdio MCP サーバーとして呼ぶときの橋渡し |
pion-browser | WebRTC のデバッグ・ブラウザ確認用ヘルパーバイナリ |
agent/internal/ — 主要パッケージ
| パッケージ | 責務 |
|---|---|
websocket | backend との永続 WS 接続(Client)とコマンドディスパッチ(HandlerRegistry、~30 個のハンドラファイル)。1 コマンド = 1 ハンドラファイルの規約 |
watcher | scanner.go(初期フルスキャン)→ fsnotify/fanotify/polling バックエンド(ライブ変更検知)→ file_event_debouncer.go(バースト集約)→ notifier.go(有限キュー、溢れたら古いものを破棄)のパイプライン |
fileio | ファイルの読み取り・書き込み・削除の primitive、アップロードセッション、glob 展開 |
security | path_validator.go — backend から渡されたパスをシンボリックリンク解決込みで検証し、.. トラバーサル・null byte を拒否する |
webrtc | NAS ファイルの直接ダウンロード機能(P2P 転送)の agent 側実装 |
messages | WebSocket プロトコルのメッセージ型。BaseMessage(手書き)+ messages_generated.go(自動生成、後述) |
config | 設定の読み込み・優先順位解決、root(監視対象ディレクトリ)の定義、デバイス認証情報の保存 |
cliproviders | ローカル CLI プロバイダ(Claude Code / Codex)のサブプロセス管理と、承認・ツール呼び出し用の stdio MCP bridge |
aiprovisioner | AI Member(display_name を持ち isolation_mode != NONE の ServiceAccount)のために Claude Code / Codex サブプロセスを起動する Spawner 抽象化 |
containerctl | AI Member サブプロセスの分離実行に使うコンテナランタイム(docker / podman / containerd)を抽象化 |
mount | rclone + FUSE で WebDAV 経由の NAS をローカルにマウントする(astar mount の実処理) |
updater | 自己更新(version.json ポーリング、バイナリ検証、置換、Docker 環境向け更新) |
docx / pdf | Office / PDF ファイルからのローカルテキスト抽出 |
errors | ユーザー向けエラー分類(UserError — 日本語の actionable メッセージ + Unwrap() で生エラーを保持) |
webui | agent 起動時にホストされるローカルセットアップ UI(登録コード入力) |
logger / format / mimeutil / pathenv / parentwatch / systemd | ロギング・フォーマット・MIME判定・PATH補正・親プロセス監視・systemd連携の小さなインフラユーティリティ |
watcher の auto モードは Linux/macOS で fsnotify に解決してはいけない。 inotify/kqueue はディレクトリ単位で watch を張るため、fs.inotify.max_user_watches の上限に達すると新規ファイルのイベントを静かに落とす。auto モードは fanotify かポーリングを選ぶ設計になっている(ASTAR_AGENT_ENABLE_FANOTIFY=0 で fanotify を強制無効化できる)。Windows の fsnotify はこの制約の対象外。
AsyncAPI プロトコル契約
WebSocket プロトコルの SSoT は Kotlin 側の AgentMessages.kt。手で agent/asyncapi.yaml や messages_generated.go を編集してはいけません。
Kotlin AgentMessages.kt (SSoT)
│ ./gradlew generateAgentMessages
▼
agent/asyncapi.yaml (自動生成)
│ go generate ./internal/messages/...
▼
messages_generated.go (自動生成)
CI がこのチェーンの再生成 diff をチェックしており、生成物が古いままだとビルドが落ちます。
multi-root 対応
agent は複数の監視対象ディレクトリ(root)を同時に扱えるよう multi-root 化されています。config.Root が 1 つの root を表し、internal/watcher/multiroot_manager.go の MultiRootManager が root ごとに watcher + scanner のペアをファンアウトします。websocket.Client 側の呼び出し規約(SetFileWatcher/SetScanner/performInitialScan など)は単一インスタンス時代のまま変わっておらず、MultiRootManager がその単一インスタンスであるかのように振る舞う設計です。
パスの扱いには注意が必要です。agent 側の RelativePath は basePath 相対、backend 側の DocumentNode.relativePath は workspace 相対で、両者は直接比較できません(deviceRelativePath を介して変換する)。
開発時の起動・テスト
cd agent && go test ./... # watcher/websocket の goleak リークテストを green に保つ
- クロスコンパイルは
agent/Makefile経由。 - Tauri サイドカービルドは
CGO_ENABLED=0のバイナリをfrontend/src-tauri/binaries/に生成する。 dev-lifecycleskill(lifecycle.sh start agent)を使うと、ソースからビルドして worktree ごとのランタイムディレクトリに配置される(Version="dev"により自己更新は無効化される)。設定ディレクトリは~/.astar-agent-dev/<port>/(worktree slot で名前空間分離)。- 手動でローカル起動する場合は
--config-dirを明示すること。--config-dirを省略した複数 agent は本番と同じ~/.astar-agent/を共有し、device-auth.jsonを後勝ちで上書きし合う既知のハザードがある。
ローカル Web UI のポートは本番が 31415 固定、dev/worktree インスタンスは本番 agent と衝突しないよう 31500 + slot を使う。
参照ソース
agent/CLAUDE.md(2026-07-03 時点の規約・構造)agent/README.md(インストール手順・配布経路)agent/internal/実コード
agent/REFACTORING.md(2025-12)は当時のリファクタ計画の歴史文書で、現在の構造とは一致しない箇所があるため参照しないでください。