astar CLI
astar は backend の Tool Router に対する薄いターミナルクライアントです。ローカルにロジックはほとんど無く、ほぼすべてのサブコマンドはそのまま backend に転送され、backend 側でレンダリングされます。
実パッケージ一覧
cli/
├── main.go # サブコマンドの switch はここだけ
├── internal/
│ ├── agentbinary/ # astar-agent バイナリの解決
│ ├── auth/ # SA トークン・device flow OAuth
│ ├── client/ # backend API クライアント
│ ├── doctor/ # 接続診断
│ ├── output/ # --format/--fields レンダリング
│ └── updater/ # 自己更新
└── skills/astar/ # Claude Code / Codex 向け同梱 skill
internal/commands/ のような verb 別パッケージ分割は存在しません。main.go の switch がサブコマンドの全体です。
| パッケージ | 役割 |
|---|---|
agentbinary | astar mount / astar unmount が exec 委譲する先の astar-agent バイナリを解決する。自分と同じディレクトリを優先し、次に $PATH を探す。astar doctor のバイナリ有無報告にも使われる |
auth | Service Account トークンと device flow OAuth(deviceflow.go)による認証、認証情報の保存 |
client | backend API へのリクエスト送信。env → header 変換(後述)もここ |
doctor | astar doctor の接続診断ロジック |
output | --format(json/table/tsv)・--fields・--output(ダウンロード先)のクライアント側レンダリング |
updater | astar update の自己更新(ダウンロード・検証・置換) |
何ができるか
ローカル実装(main.go の switch にある verb だけ): login / logout / update / use(ワークスペース切り替え) / doctor / mount / unmount / --version / 出力レンダリングフラグ。
それ以外は全部 backend に生転送されます。POST /api/v1/cli(AstarCliController.kt、core/mcp/api/controller/)が受け取り、AI エージェントと同じ AstarToolRouter を通します。コマンドは <group> <subcommand> [--arg value ...] の形式で、help / <group> help で一覧を取得できます。
新しいサーバー側コマンドを追加するときは backend の router(Kotlin)に足す — main.go に新しい switch case を足さないこと。この switch は上記のクライアント専用 verb のためだけに存在し、ここに server-side tool 用の case を足すと router のゲーティングを迂回し、backend 側と重複したロジックになる。
破壊的操作のセマンティクス(SEC-002)— ここは「直さない」
- 裸の
deleteはローカルで確認を挟まず即コミットされる(Unix のrmと同じ意味論)。確認ヘビーな UI に慣れていると意外に見えるが、意図的な設計。 CanonicalVerbs.DESTRUCTIVE_VERBS(backend のcore/mcp/infrastructure/annotation/CanonicalVerbs.kt)とalwaysConfirm(ToolGate/AgentOrchestrator/AgentToolLoopPhase)はすべて backend 側にあり、CLI にクライアント側の確認ロジックは存在しない。--dry-runでプレビューのみ、--confirm falseでその呼び出し限定のプレビューデフォルト動作に戻せる。
認証・ヘッダ
- 主認証は SA トークン、
Authorization: Bearerのみ。CLI はX-Tenant-Idを送らず、テナントはトークンから backend 側で解決される。 - go-agent が AI Member セッション用に CLI をスポーンするときだけ、
env → headerパターンでアンビエントコンテキストを渡す(internal/client/client.go):ASTAR_CLI_SESSION_TICKET(env) →X-Cli-Session-Ticket(header)ASTAR_CURRENT_WORKSPACE_ID(env) →X-Astar-Ambient-Workspace-Id(header)
新しいヘッドレス/アンビエントコンテキストを追加する場合も、この env-in → header-out パターンに合わせること。新しい ad-hoc フラグや設定ファイルを発明しない。
Claude Code / Codex 向け同梱 skill
cli/skills/astar/ に SKILL.md.claude / SKILL.md.codex / CLAUDE.md.fragment があり、cli/scripts/install-cli.sh が astar 本体と一緒にダウンロードして、ユーザーのローカル Claude Code / Codex の skill ディレクトリに配置します。これにより、事務員が「案件」「証拠説明書」などの話題を出したときにローカルの AI エージェントが astar コマンドの有無・接続状態を確認し、使い方を案内できるようになります。
backend との関係 — core/mcp であって core/cliexec ではない
astar CLI の実体は core/mcp モジュールです。AstarCliController(POST /api/v1/cli)が AstarToolRouter を呼び出し、AI エージェントが使うのと同じツール群を CLI からも実行できるようにしています。
紛らわしいですが、core/cliexec は astar CLI とは別物です。名前が似ていて実際に混同しやすいので明記します。core/cliexec が扱うのは「ローカル CLI プロバイダ(Claude Code / Codex)セッション」——顧客の go-agent が AI Member のためにスポーンする claude / codex サブプロセスと、そのプロセスからの承認要求・ask_user 呼び出しを backend にブリッジする仕組みです(CliBridgeRequestDispatcher、CliSessionRegistry)。フローはこうです。
CLI subprocess (claude / codex)
│ MCP tool 呼び出し (astar__request_approval / astar__ask_user)
▼
Go-Agent stdio MCP bridge
│ WebSocket 経由で CliSessionMcpRequestMessage を転送
▼
AgentWebSocketHandler → core/cliexec (CliSessionRegistry / CliBridgeRequestDispatcher)
astar バイナリのユーザーが打つコマンドはこの経路を一切通りません。core/cliexec の CliSession は「AI Member としてローカルで動く Claude Code/Codex の 1 会話」を指し、astar CLI の「ターミナルから backend の tool router を叩く 1 リクエスト」とは無関係です。
ビルド
cd cli && go test ./...
cli-ci.ymlがgo test ./...に加えて、Auth0 の値を ldflags で焼き込んだリリースビルドを実行する(-X astar-cli/internal/auth.Auth0Domain/ClientID/Audience、値はcli/Makefile経由でinfrastructure/deploy.envから)。- 新しいビルドパス(2 本目のバイナリターゲットなど)を追加する場合も同じ ldflags セットを注入すること。省略すると Auth0 設定なしでビルドされてしまう。
参照ソース
cli/CLAUDE.mdcli/実コード(main.go/internal/*)backend/.../core/mcp/api/controller/AstarCliController.ktbackend/.../core/cliexec/(domain/model/CliSession.kt, domain/service/CliBridgeRequestDispatcher.kt, api/controller/CliSessionController.kt)