aiterm-mcp 0.12.1 → 0.12.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +21 -5
- package/README.md +33 -5
- package/dist/core.js +426 -132
- package/dist/index.js +39 -1
- package/dist/runtime-error-store.js +844 -0
- package/dist/runtime-error-worker.js +24 -0
- package/dist/runtime-errors-cli.js +66 -0
- package/package.json +3 -2
package/README.ja.md
CHANGED
|
@@ -22,7 +22,12 @@
|
|
|
22
22
|
|
|
23
23
|
**言葉でなく実測で:** このリポジトリ自身の 203 テストで、`pty_read` はコンテキストに載るトークンを生ログの **約 7.1 分の 1** に減らす。しかも pass/fail の判定は畳んでも残る。→ [組み込みシェルツールとの使い分け](#組み込みシェルツールとの使い分け)
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
10 ツール: 6 つの **PTY ツール**(`pty_open` / `pty_send` / `pty_read` / `pty_key` / `pty_close` / `pty_list`)で 1 本の永続端末を開き・操作し・読む。加えて 3 つの **エージェント起動ツール**(`codex_agent` / `grok_agent` / `composer_agent`)が、別のコーディングエージェントの TUI を新しい端末の中に起動し、`diagnostics` が安全な factory readiness を返す。バックエンドは **tmux** なので、MCP サーバや AI クライアントが再起動してもセッションは生き残る。
|
|
26
|
+
|
|
27
|
+
**v0.12.2 は release candidate(公開待ち)です。** factory diagnostics と local
|
|
28
|
+
runtime-error store は canonical dotagents config の `collection.enabled: true` が明示された
|
|
29
|
+
場合だけ収集し、既定OFF、network送信は行いません。npm公開、tag、CI、registry登録、registry由来install
|
|
30
|
+
の確認は未実施です。
|
|
26
31
|
|
|
27
32
|
**状態:** 開発継続中 · この分野では新参で、別の形に賭けている([既存手段との比較](#既存手段との比較)参照)· 動作対象は Linux · WSL2 · macOS · Windows ネイティブ(core PTY ツール。`agent_done` は現時点では POSIX/WSL/macOS のみ)· MIT · [変更履歴](CHANGELOG.md)。
|
|
28
33
|
|
|
@@ -66,7 +71,7 @@ pty_send("codex1", "also fix the imports it broke", { wait: "agent_done" })
|
|
|
66
71
|
| `grok_agent` | Grok Build の `grok-build` モデル(xAI) | `prompt?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`), `cwd?`, `session_name?`, `agent_done?` |
|
|
67
72
|
| `composer_agent` | Grok Build の `grok-composer-2.5-fast` モデル(xAI) | `grok_agent` と同じ |
|
|
68
73
|
|
|
69
|
-
各ベンダーの CLI が導入・認証済みであること(`codex_agent` は `codex`、Grok 系 2 つは `grok`)。バイナリは `CODEX_BIN` / `GROK_BIN` → `~/.local/bin/codex` / `~/.grok/bin/grok` → `PATH` の順で解決する。前提は **session を作る前に**検証する——`grok_agent` / `composer_agent` は範囲外の `reasoning_effort` を先に弾き(値集合は固定=`low`/`medium`/`high`/`xhigh`/`max`)、CLI バイナリ不在・実在しない `cwd` は 3 つとも失敗する。前提(`reasoning_effort`・バイナリ・`cwd`)で弾かれた起動は **session の残骸をゼロ**にして返し、起動キーストロークを送れなければ session を畳む。(初回 prompt wait を使わない場合、その先でベンダー CLI が実際に立ち上がったか・認証できたかは aiterm は検証しない——起動できたかは session を読んで確認する。)(`codex_agent` は Codex の受理値が版で変わるため、`reasoning_effort` を検証せず config override〔`-c model_reasoning_effort=…`〕として Codex CLI へ渡す。)`cwd` は絶対パスで渡す——`~` は展開されない。`agent_done` は launch ごとの managed vendor home を使い、通常の hook file は書き換えない。Codex は managed `CODEX_HOME` に `auth.json` だけを symlink し、`config.toml` はコピーする。Grok/Composer はさらに `GROK_HOME` と `HOME` を隔離し、compat hook/plugin
|
|
74
|
+
各ベンダーの CLI が導入・認証済みであること(`codex_agent` は `codex`、Grok 系 2 つは `grok`)。バイナリは `CODEX_BIN` / `GROK_BIN` → `~/.local/bin/codex` / `~/.grok/bin/grok` → `PATH` の順で解決する。前提は **session を作る前に**検証する——`grok_agent` / `composer_agent` は範囲外の `reasoning_effort` を先に弾き(値集合は固定=`low`/`medium`/`high`/`xhigh`/`max`)、CLI バイナリ不在・実在しない `cwd` は 3 つとも失敗する。前提(`reasoning_effort`・バイナリ・`cwd`)で弾かれた起動は **session の残骸をゼロ**にして返し、起動キーストロークを送れなければ session を畳む。(初回 prompt wait を使わない場合、その先でベンダー CLI が実際に立ち上がったか・認証できたかは aiterm は検証しない——起動できたかは session を読んで確認する。)(`codex_agent` は Codex の受理値が版で変わるため、`reasoning_effort` を検証せず config override〔`-c model_reasoning_effort=…`〕として Codex CLI へ渡す。)`cwd` は絶対パスで渡す——`~` は展開されない。`agent_done` は launch ごとの managed vendor home を使い、通常の hook file は書き換えない。Codex は managed `CODEX_HOME` に `auth.json` だけを symlink し、`config.toml` はコピーする。Grok/Composer はさらに `GROK_HOME` と `HOME` を隔離し、compat hook/plugin 混入を抑える。Grok OAuth は検証済みの通常auth正本をvendor所有の `GROK_AUTH_PATH` で渡し、managed homeにauth/lockのsymlinkやcopyを作らない。refresh lockとatomic replacementはGrok自身が所有する。初回の未 bind `pty_send({ wait: "agent_done" })` は、vendor TUI の入力欄が出るまで待ち、入力受付状態でなければ文字列を送らず送信前エラーにする。`codex_agent` launcher の `wait:"agent_done"` も同じく `prompt` と `agent_done:true` が必須。TUI が入力欄 ready にならない場合は prompt を送らず、`initial_prompt=not_sent` として session を調査可能なまま残す。起動時 prompt が `pending`/`sent` の間は、混入防止のため通常 `pty_send` も拒否する。手動介入は `pty_key`、または意図的な `pty_send(..., force:true)` で行う。`agent_done` は `getuid`・安全な一時ファイル・hard link 検査など POSIX ファイルシステム前提を使うため、対応は Linux / WSL2 / macOS。Windows ネイティブでは core PTY と agent launcher は使えるが、`agent_done` はまだ未対応。
|
|
70
75
|
|
|
71
76
|
**Claude launcher はあえて無い**し、エージェント間のプロトコルも無い: aiterm の役目は、あなたの Claude(や任意の MCP クライアント)が*他の*エージェントに手を伸ばして端末を操作できるようにすること。起動したエージェントは単なるもう 1 本の永続セッションなので、この README の他のすべて(トークン削減読取・完了検出・人の `attach` での監視/介入)がそのまま効く。
|
|
72
77
|
|
|
@@ -129,7 +134,7 @@ claude mcp add --scope user --transport stdio aiterm -- npx -y aiterm-mcp
|
|
|
129
134
|
Claude Code を再起動して、接続を確認:
|
|
130
135
|
|
|
131
136
|
```bash
|
|
132
|
-
/mcp # aiterm が connected・
|
|
137
|
+
/mcp # aiterm が connected・10 ツール公開、と出る
|
|
133
138
|
```
|
|
134
139
|
|
|
135
140
|
最初のセッション——4 回の呼び出しで、1 個の永続端末:
|
|
@@ -167,7 +172,7 @@ MCP クライアントが aiterm を stdio 越しにプログラムから駆動
|
|
|
167
172
|
|
|
168
173
|
```mermaid
|
|
169
174
|
flowchart LR
|
|
170
|
-
AI["AI / MCP client<br/>(the orchestrator)"] -->|"pty_send · codex_agent<br/>grok_agent · composer_agent"| S["aiterm-mcp<br/>stdio MCP ·
|
|
175
|
+
AI["AI / MCP client<br/>(the orchestrator)"] -->|"pty_send · codex_agent<br/>grok_agent · composer_agent · diagnostics"| S["aiterm-mcp<br/>stdio MCP · 10 tools"]
|
|
171
176
|
S -->|"pty_read<br/>token-reduced"| AI
|
|
172
177
|
S -->|"tmux send-keys<br/>capture-pane"| P["persistent PTYs<br/>tmux · survive restarts"]
|
|
173
178
|
P -->|"ssh · docker · repl"| R["nested<br/>remote · container · REPL"]
|
|
@@ -248,6 +253,15 @@ aiterm は同じ核心の洞察——端末を出会いの場にする——を
|
|
|
248
253
|
| `pty_key` | 制御キーを送る | `session_id`, `key`(`C-c`/`Enter`/`Up`…) |
|
|
249
254
|
| `pty_close` | セッションを閉じる | `session_id` |
|
|
250
255
|
| `pty_list` | セッション一覧 | (なし) |
|
|
256
|
+
| `diagnostics` | 機械可読 JSON による read-only factory readiness | (なし) |
|
|
257
|
+
|
|
258
|
+
`diagnostics` は PTY やエージェントを起動しない。パッケージ版、MCP 呼出 readiness、read-only な PTY 一覧要約、bounded runtime-error-store status、任意 vendor launcher の可用性だけを返す。path・環境値・認証情報・コマンド本文・PTY 出力・raw log は意図的に返さない。通常未設定の任意依存は `not_applicable`、安全に確定できない状態は `unverified` と表す。
|
|
259
|
+
|
|
260
|
+
### ローカル runtime error snapshot
|
|
261
|
+
|
|
262
|
+
`aiterm-runtime-errors snapshot` は dotagents factory adapter 向けに、製品所有のローカル snapshot を機械可読 JSON で返す。canonical dotagents factory-reporter config が schema-exact、host profile が実行 OS と一致し、`collection.enabled` が JSON boolean `true` の時だけ収集する。reporting field は schema 検証するが endpoint/credential file へ接続・読取せず network I/O も行わない。観測 API は core owner layer の固定3 code(PTY dependency・persistence・任意 vendor launcher)だけを受け、保存するのも固定 template と aggregate metadata(SHA-256 fingerprint、count、first/last、status、monotonic sequence)だけ。exception、stderr/stdout、stack、prompt、PTY/transcript/event body、path、任意 context は受け付けない。保存済み JSON も top/record exact・固定定義一致・fingerprint 再計算を通し、明示 DTO だけを返す。
|
|
263
|
+
|
|
264
|
+
consumer は `aiterm-runtime-errors snapshot` を読み、durable ingestion 後に `aiterm-runtime-errors ack --cursor N` を呼ぶ。運用上の明示操作は `resolve|reopen --fingerprint SHA256`。MCP からの収集・diagnostic read は timeout 付き child process に隔離し、FIFOや停止 filesystem が端末本体を止めない。store mutation は期限付き bakery ticket queue で直列化する。各waiterは PID+process start identity+owner token を持つ再利用されない固有ticketを所有するため、死んだownerだけを固有名で除去でき、固定path回収のABAを作らない。POSIX state は `$XDG_STATE_HOME/aiterm-mcp/`(既定 `~/.local/state/aiterm-mcp/`)へ atomic replacement で置き、every read で owner/mode を再検証する。Windows native は `%LOCALAPPDATA%\aiterm-mcp\` で current SID の非継承 FullControl ACE 1件だけへ DACL を再構築し readback する。今回 Windows は path/DACL/timeout の純粋テストだけであり、新しい実機統合成功は主張しない。
|
|
251
265
|
|
|
252
266
|
### 対話エージェント起動ツール
|
|
253
267
|
|
|
@@ -259,7 +273,7 @@ aiterm は同じ核心の洞察——端末を出会いの場にする——を
|
|
|
259
273
|
| `grok_agent` | Grok Build の `grok-build` モデル(xAI) | `prompt?`, `reasoning_effort?`(`low`/`medium`/`high`/`xhigh`/`max`), `cwd?`, `session_name?`, `agent_done?` |
|
|
260
274
|
| `composer_agent` | Grok Build の `grok-composer-2.5-fast` モデル(xAI) | `grok_agent` と同じ |
|
|
261
275
|
|
|
262
|
-
各ベンダーの CLI が導入・認証済みであること(`codex_agent` は `codex`、Grok 系 2 つは `grok`)。バイナリは `CODEX_BIN` / `GROK_BIN` → `~/.local/bin/codex` / `~/.grok/bin/grok` → `PATH` の順で解決する。前提はセッション作成前に検証し(grok/composer は範囲外の `reasoning_effort` を弾く。CLI 不在・実在しない `cwd` は 3 つとも失敗)、起動に失敗してもセッションの残骸は残さない。詳細は [その端末の中に他のコーディングエージェントを起動する](#2-その端末の中に他のコーディングエージェントを起動する--オーケストレーションの旗艦)。`cwd` は絶対パスで渡す——`~` は展開されない。`agent_done` は hook-backed で、Codex/Grok/Composer は Linux/WSL2/macOS の後続 `pty_send(wait:"agent_done")` で実 smoke 済み。Codex は launcher の `prompt + wait:"agent_done"` も実 smoke 済み。Windows ネイティブでは agent launcher は使えるが `agent_done` はまだ未対応。Codex の managed `CODEX_HOME` は `auth.json` だけを symlink し、`config.toml` をコピーし、`hooks.json` は aiterm が所有する。初回の未 bind agent send では `pty_send({ wait:"agent_done" })` が vendor TUI の入力欄を待ち、未 ready なら送信前エラーにする。`codex_agent` launcher の `wait:"agent_done"` は `prompt` と `agent_done:true` が必須で、TUI ready 後にだけ初回 prompt を送る。入力欄 ready にならない場合は prompt を送らず、`initial_prompt=not_sent` を返して session を残す。Grok OAuth mode では
|
|
276
|
+
各ベンダーの CLI が導入・認証済みであること(`codex_agent` は `codex`、Grok 系 2 つは `grok`)。バイナリは `CODEX_BIN` / `GROK_BIN` → `~/.local/bin/codex` / `~/.grok/bin/grok` → `PATH` の順で解決する。前提はセッション作成前に検証し(grok/composer は範囲外の `reasoning_effort` を弾く。CLI 不在・実在しない `cwd` は 3 つとも失敗)、起動に失敗してもセッションの残骸は残さない。詳細は [その端末の中に他のコーディングエージェントを起動する](#2-その端末の中に他のコーディングエージェントを起動する--オーケストレーションの旗艦)。`cwd` は絶対パスで渡す——`~` は展開されない。`agent_done` は hook-backed で、Codex/Grok/Composer は Linux/WSL2/macOS の後続 `pty_send(wait:"agent_done")` で実 smoke 済み。Codex は launcher の `prompt + wait:"agent_done"` も実 smoke 済み。Windows ネイティブでは agent launcher は使えるが `agent_done` はまだ未対応。Codex の managed `CODEX_HOME` は `auth.json` だけを symlink し、`config.toml` をコピーし、`hooks.json` は aiterm が所有する。初回の未 bind agent send では `pty_send({ wait:"agent_done" })` が vendor TUI の入力欄を待ち、未 ready なら送信前エラーにする。`codex_agent` launcher の `wait:"agent_done"` は `prompt` と `agent_done:true` が必須で、TUI ready 後にだけ初回 prompt を送る。入力欄 ready にならない場合は prompt を送らず、`initial_prompt=not_sent` を返して session を残す。Grok OAuth mode ではhook/config隔離をlaunchごとに維持し、検証済みの通常auth正本を`GROK_AUTH_PATH`でvendorへ渡す。managed homeにauth/lockは作らない。OAuth auth 不在ならセッション残骸なしで失敗する。
|
|
263
277
|
|
|
264
278
|
エージェントの回答が `wait:"agent_done"` の画面 tail(ペイン高 ≒ 24 行)より長くて切れたら、`pty_read({ agent_transcript: true })` で全文回収する。managed home 配下の vendor 構造化 transcript から、直近完了ターンの最終 assistant メッセージを平文で返す(再プロンプト不要)。Codex は Stop hook の `turn_id` で join、Grok/Composer は最後の実ユーザー行より後ろの assistant 行を採る。読み取り専用で、`screen`/`full`/`rtk`/`line_range`/`wait` とは併用不可(`lines` のみ可)。transcript 不在・非 agent session・抽出不能はいずれも明示エラー(黙って空を返さない)。
|
|
265
279
|
|
|
@@ -277,6 +291,8 @@ aiterm は同じ核心の洞察——端末を出会いの場にする——を
|
|
|
277
291
|
|
|
278
292
|
`pty_send` は送信前に破壊的コマンド(`rm -rf /`, `mkfs`, `dd of=/dev/…`, `DROP TABLE` 等)を遮断し(`force: true` で越える)、ESC・ブラケットペースト終端などをサニタイズする。`pty_read` は既定で制御文字を無害化して返す(`raw: true` はバイトをそのまま返す)。これは**サンドボックスではなく tripwire**([既知の制約](#既知の制約バグではなく仕様)参照)。
|
|
279
293
|
|
|
294
|
+
1回の `pty_send` が受理する本文はUTF-8で最大64KiB。同一sessionへの送信はaiterm processをまたいで直列化し、chunk同士の混線を防ぐ。macOSでは長いPTY入力の欠落を避けるためUTF-8境界を壊さない256-byte単位でtmux pasteし、Linux/WSLでは上限内を1回でpasteする。途中chunkが失敗した場合は部分送信済みであることを明示し、自動でEnterを押さない。送信processの異常終了でlockが残った場合は送信前にfail-closedする。そのsessionを `pty_close` して作り直すか、全sessionを破棄できる場合だけ `pty_kill_all` で安全に掃除する。
|
|
295
|
+
|
|
280
296
|
## 人が覗く
|
|
281
297
|
|
|
282
298
|
セッションは共有 tmux ソケット上にある。`pty_open`(および各エージェント起動ツール)の戻り値に表示される `tmux -S … attach -t <id>` で人間が同じ端末に入って介入できる(抜けるのは `Ctrl-b d`)——起動した Codex/Grok/Composer のセッションが走るのを覗いたり、作業の途中で AI からキーボードを奪ったりも。Windows ネイティブではセッションが WSL 内にあるため、表示は WSL 形(`wsl tmux -S … attach -t <id>`)になる。
|
package/README.md
CHANGED
|
@@ -22,7 +22,13 @@
|
|
|
22
22
|
|
|
23
23
|
**Measured, not claimed:** on this repo's own 203-test suite, a `pty_read` puts **~7.1× fewer tokens** in your context than the raw log — and the pass/fail verdict survives the fold. → [When to reach for it vs. the built-in shell](#when-to-reach-for-it-vs-the-built-in-shell)
|
|
24
24
|
|
|
25
|
-
|
|
25
|
+
Ten tools: six **PTY tools** — `pty_open` / `pty_send` / `pty_read` / `pty_key` / `pty_close` / `pty_list` — to open, drive, and read one persistent terminal, three **agent launchers** — `codex_agent` / `grok_agent` / `composer_agent` — that each start another coding agent's TUI inside a fresh one, and `diagnostics` for safe factory readiness. The backend is **tmux**, so sessions survive even if the MCP server or the AI client restarts.
|
|
26
|
+
|
|
27
|
+
**v0.12.2 was published on 2026-07-13.** Factory diagnostics and the local
|
|
28
|
+
runtime-error store collect only when canonical dotagents config explicitly sets
|
|
29
|
+
`collection.enabled: true`; collection is off by default and performs no network
|
|
30
|
+
I/O. npm `latest`, provenance CI, tag / GitHub Release, Official MCP Registry
|
|
31
|
+
registration, and a registry-derived isolated install were verified.
|
|
26
32
|
|
|
27
33
|
**Status:** actively maintained · the newcomer here, betting on a different shape (see [vs. the alternatives](#vs-the-alternatives)) · runs on Linux · WSL2 · macOS · native Windows for the core PTY tools (`agent_done` is POSIX/WSL/macOS only for now) · MIT · see the [CHANGELOG](CHANGELOG.md).
|
|
28
34
|
|
|
@@ -66,7 +72,7 @@ One call per model, so the tool name itself tells you which model you get:
|
|
|
66
72
|
| `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?`, `agent_done?` |
|
|
67
73
|
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?`, `agent_done?` |
|
|
68
74
|
|
|
69
|
-
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are checked **before** a session exists: empty `model` values and any `reasoning_effort` for `grok_agent` / `composer_agent` are rejected up front; a missing CLI binary or a nonexistent `cwd` fails for all three. A rejected launch leaves **zero leftover session** behind, and if the launch keystroke itself can't be delivered aiterm tears the session down. (Without an initial prompt wait, aiterm does *not* then verify the vendor CLI actually started or authenticated — read the session to confirm the agent came up.) `codex_agent` forwards `model` as `-m` and `reasoning_effort` as `-c model_reasoning_effort=…` without validating the effort value, since Codex's accepted values vary by version. Grok/Composer reject `reasoning_effort`: Grok CLI `--effort` is only for headless `grok -p`, and the interactive TUI ignores it with a warning. Pass an absolute path for `cwd` — `~` is not expanded. Codex launch responses always report the effective model/effort and where each came from (argument, terminal-config inheritance, or CLI default), with an explicit warning when the effective effort is `ultra` (max reasoning plus proactive automatic delegation). `agent_done` uses launch-local managed vendor homes and does not edit your normal hook files; Codex links only `auth.json` and copies `config.toml` into its managed `CODEX_HOME` — explicitly passed `model` / `reasoning_effort` values also rewrite the matching top-level pins in that copy, so terminal pins don't silently leak into the child — while Grok/Composer additionally isolate `GROK_HOME` and `HOME` to suppress compat hook/plugin contamination. Grok OAuth
|
|
75
|
+
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are checked **before** a session exists: empty `model` values and any `reasoning_effort` for `grok_agent` / `composer_agent` are rejected up front; a missing CLI binary or a nonexistent `cwd` fails for all three. A rejected launch leaves **zero leftover session** behind, and if the launch keystroke itself can't be delivered aiterm tears the session down. (Without an initial prompt wait, aiterm does *not* then verify the vendor CLI actually started or authenticated — read the session to confirm the agent came up.) `codex_agent` forwards `model` as `-m` and `reasoning_effort` as `-c model_reasoning_effort=…` without validating the effort value, since Codex's accepted values vary by version. Grok/Composer reject `reasoning_effort`: Grok CLI `--effort` is only for headless `grok -p`, and the interactive TUI ignores it with a warning. Pass an absolute path for `cwd` — `~` is not expanded. Codex launch responses always report the effective model/effort and where each came from (argument, terminal-config inheritance, or CLI default), with an explicit warning when the effective effort is `ultra` (max reasoning plus proactive automatic delegation). `agent_done` uses launch-local managed vendor homes and does not edit your normal hook files; Codex links only `auth.json` and copies `config.toml` into its managed `CODEX_HOME` — explicitly passed `model` / `reasoning_effort` values also rewrite the matching top-level pins in that copy, so terminal pins don't silently leak into the child — while Grok/Composer additionally isolate `GROK_HOME` and `HOME` to suppress compat hook/plugin contamination. Grok OAuth passes the validated normal auth canonical file through vendor-owned `GROK_AUTH_PATH`; managed homes contain no auth/lock symlink or copy, so refresh locking and atomic replacement stay in Grok itself. Before the first unbound `pty_send({ wait: "agent_done" })`, aiterm waits for the vendor TUI's input prompt and fails before sending if the prompt is not ready, avoiding dropped startup input. `codex_agent` launcher `wait:"agent_done"` has the same requirement and is only valid with both `prompt` and `agent_done:true`; if the TUI is not ready, the prompt is not sent and the session is left inspectable with `initial_prompt=not_sent`. While an initial prompt is still `pending`/`sent`, ordinary `pty_send` is rejected to prevent mixed input; manual takeover can still use `pty_key`, or `pty_send(..., force:true)` if you intentionally want to type into that live TUI. `agent_done` currently requires POSIX filesystem semantics (`getuid`, secure temp files, hard-link checks), so it is supported on Linux, WSL2, and macOS; native Windows can still use the core PTY tools and agent launchers without `agent_done`.
|
|
70
76
|
|
|
71
77
|
There is deliberately **no Claude launcher**, and no protocol between the agents: aiterm's job is to let your Claude (or any MCP client) reach for *other* agents and drive their terminals. Because a launched agent is just another persistent session, everything else in this README applies to it: token-reduced reads, completion detection, and a human `attach` to watch or take over.
|
|
72
78
|
|
|
@@ -129,7 +135,7 @@ claude mcp add --scope user --transport stdio aiterm -- npx -y aiterm-mcp
|
|
|
129
135
|
Restart Claude Code, then verify the connection:
|
|
130
136
|
|
|
131
137
|
```bash
|
|
132
|
-
/mcp # aiterm should show as connected, exposing
|
|
138
|
+
/mcp # aiterm should show as connected, exposing 10 tools
|
|
133
139
|
```
|
|
134
140
|
|
|
135
141
|
Your first session — four calls, one persistent terminal:
|
|
@@ -167,7 +173,7 @@ The terminal is real and shared, so a human *can* jump in ([A human can watch](#
|
|
|
167
173
|
|
|
168
174
|
```mermaid
|
|
169
175
|
flowchart LR
|
|
170
|
-
AI["AI / MCP client<br/>(the orchestrator)"] -->|"pty_send · codex_agent<br/>grok_agent · composer_agent"| S["aiterm-mcp<br/>stdio MCP ·
|
|
176
|
+
AI["AI / MCP client<br/>(the orchestrator)"] -->|"pty_send · codex_agent<br/>grok_agent · composer_agent · diagnostics"| S["aiterm-mcp<br/>stdio MCP · 10 tools"]
|
|
171
177
|
S -->|"pty_read<br/>token-reduced"| AI
|
|
172
178
|
S -->|"tmux send-keys<br/>capture-pane"| P["persistent PTYs<br/>tmux · survive restarts"]
|
|
173
179
|
P -->|"ssh · docker · repl"| R["nested<br/>remote · container · REPL"]
|
|
@@ -250,6 +256,15 @@ On top of that sits a productized layer a raw tmux bridge doesn't have: **token-
|
|
|
250
256
|
| `pty_key` | Send a control key | `session_id`, `key` (`C-c`/`Enter`/`Up`…) |
|
|
251
257
|
| `pty_close` | Close a session | `session_id` |
|
|
252
258
|
| `pty_list` | List sessions (agent rows carry `agent=<kind>` metadata) | (none) |
|
|
259
|
+
| `diagnostics` | Read-only factory readiness as machine-readable JSON | (none) |
|
|
260
|
+
|
|
261
|
+
`diagnostics` never starts a PTY or agent. It reports package version, MCP call readiness, a read-only PTY-list summary, bounded runtime-error-store status, and optional vendor-launcher availability. It deliberately excludes paths, environment values, credentials, command text, PTY output, and raw logs; normal unset optional dependencies are `not_applicable`, while an indeterminate probe is `unverified`.
|
|
262
|
+
|
|
263
|
+
### Local runtime error snapshot
|
|
264
|
+
|
|
265
|
+
`aiterm-runtime-errors snapshot` exposes a machine-readable, product-owned local snapshot for the dotagents factory adapter. Collection is fail-closed unless the canonical dotagents factory-reporter config is schema-exact, its host profile matches the executing OS, and it contains the JSON boolean `collection.enabled: true`; reporting fields are schema-validated but endpoints and credential files are never contacted, and the store performs no network I/O. The only accepted observations are three fixed codes owned by the core boundary (PTY dependency, persistence, and optional vendor launcher). Stored data is limited to fixed templates and aggregate metadata (SHA-256 fingerprint, count, first/last seen, status, and monotonic sequence); exceptions, stderr/stdout, stacks, prompts, terminal/transcript/event bodies, paths, and arbitrary context cannot enter the API. Persisted JSON is revalidated with exact top/record fields and a recomputed fingerprint before explicit DTO projection.
|
|
266
|
+
|
|
267
|
+
Consumer flow is `aiterm-runtime-errors snapshot`, then `aiterm-runtime-errors ack --cursor N` after durable ingestion. Operators can use `resolve|reopen --fingerprint SHA256`. MCP collection and diagnostic reads run in timeout-bounded child processes, so a FIFO or stalled filesystem cannot block terminal work; child failure emits only the fixed store diagnostic. Store mutation uses a bounded bakery ticket queue: every waiter owns a never-reused ticket containing PID, process-start identity, and an owner token, so dead owners are removed by unique filename without fixed-path reclaim ABA. Worker deadlines use forced termination so a SIGTERM-ignoring child cannot mutate state after timeout. POSIX state is atomically replaced under `$XDG_STATE_HOME/aiterm-mcp/` (default `~/.local/state/aiterm-mcp/`) with owner/mode rechecked on every read. Windows native uses `%LOCALAPPDATA%\aiterm-mcp\`; each DACL is rebuilt and read back as one non-inherited FullControl ACE for the current SID. Windows path/DACL/timeout behavior is covered by pure tests in this change; no new Windows integration success is claimed.
|
|
253
268
|
|
|
254
269
|
### Interactive agent launchers
|
|
255
270
|
|
|
@@ -261,7 +276,7 @@ Each launcher starts a specific vendor's interactive coding-agent TUI inside a f
|
|
|
261
276
|
| `grok_agent` | Grok Build, model `grok-4.5` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error; Grok CLI `--effort` is headless-only), `cwd?`, `session_name?`, `agent_done?` |
|
|
262
277
|
| `composer_agent` | Grok Build, model `grok-composer-2.5-fast` by default (`model?` overrides) (xAI) | `prompt?`, `model?`, `reasoning_effort?` unsupported (an explicit value is an error), `cwd?`, `session_name?`, `agent_done?` |
|
|
263
278
|
|
|
264
|
-
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are validated before a session is created: empty `model` and any Grok/Composer `reasoning_effort` are errors, while a missing CLI or nonexistent `cwd` fails for all three; a failed launch leaves no session behind. Codex forwards `model` as `-m` and `reasoning_effort` as `-c model_reasoning_effort=…`; Grok/Composer reject effort because interactive TUI does not support it (Grok CLI `--effort` is headless-only). Full details under [Launch other coding agents into that terminal](#2-launch-other-coding-agents-into-that-terminal--the-orchestration-flagship). Pass an absolute path for `cwd` — `~` is not expanded. `agent_done` is hook-backed for agent launchers; Codex/Grok/Composer have passing live smokes on Linux/WSL2/macOS for follow-up `pty_send(wait:"agent_done")`, and Codex has a live smoke for launcher `prompt + wait:"agent_done"`. Native Windows can launch agents but `agent_done` is not supported yet. Codex managed `CODEX_HOME` links only `auth.json`, copies `config.toml`, and owns its own `hooks.json`. Before the first unbound agent send, `pty_send({ wait:"agent_done" })` waits for the vendor TUI input prompt and fails before sending if it is not ready. `codex_agent` launcher `wait:"agent_done"` requires `prompt` plus `agent_done:true`; it sends the initial prompt only after the TUI is ready, and returns `initial_prompt=not_sent` without sending if the TUI is blocked before input. In Grok OAuth mode, aiterm keeps hook/config isolation per launch
|
|
279
|
+
The vendor CLI must be installed and authenticated (`codex` for `codex_agent`; `grok` for both Grok tools). aiterm resolves the binary via `CODEX_BIN` / `GROK_BIN`, then `~/.local/bin/codex` / `~/.grok/bin/grok`, then `PATH`. Prerequisites are validated before a session is created: empty `model` and any Grok/Composer `reasoning_effort` are errors, while a missing CLI or nonexistent `cwd` fails for all three; a failed launch leaves no session behind. Codex forwards `model` as `-m` and `reasoning_effort` as `-c model_reasoning_effort=…`; Grok/Composer reject effort because interactive TUI does not support it (Grok CLI `--effort` is headless-only). Full details under [Launch other coding agents into that terminal](#2-launch-other-coding-agents-into-that-terminal--the-orchestration-flagship). Pass an absolute path for `cwd` — `~` is not expanded. `agent_done` is hook-backed for agent launchers; Codex/Grok/Composer have passing live smokes on Linux/WSL2/macOS for follow-up `pty_send(wait:"agent_done")`, and Codex has a live smoke for launcher `prompt + wait:"agent_done"`. Native Windows can launch agents but `agent_done` is not supported yet. Codex managed `CODEX_HOME` links only `auth.json`, copies `config.toml`, and owns its own `hooks.json`. Before the first unbound agent send, `pty_send({ wait:"agent_done" })` waits for the vendor TUI input prompt and fails before sending if it is not ready. `codex_agent` launcher `wait:"agent_done"` requires `prompt` plus `agent_done:true`; it sends the initial prompt only after the TUI is ready, and returns `initial_prompt=not_sent` without sending if the TUI is blocked before input. In Grok OAuth mode, aiterm keeps hook/config isolation per launch and passes the validated normal auth canonical file through `GROK_AUTH_PATH`; managed homes contain no auth/lock file, and missing OAuth auth fails before a session exists.
|
|
265
280
|
|
|
266
281
|
When an agent's answer is longer than the `wait:"agent_done"` screen tail (pane height ≈ 24 lines), recover it in full with `pty_read({ agent_transcript: true })`. It returns the most recently completed turn's final assistant message in plain text, read from the vendor's structured session transcript under the managed home — no re-prompting. Codex joins on the Stop hook `turn_id`; Grok/Composer take the assistant rows after the last real user row. Read-only, and mutually exclusive with `screen`/`full`/`rtk`/`line_range`/`wait` (`lines` is allowed). A missing transcript, a non-agent session, or an unextractable message is an explicit error, never a silent empty.
|
|
267
282
|
|
|
@@ -279,6 +294,8 @@ When an agent's answer is longer than the `wait:"agent_done"` screen tail (pane
|
|
|
279
294
|
|
|
280
295
|
Before sending, `pty_send` blocks destructive commands (`rm -rf /`, `mkfs`, `dd of=/dev/…`, `DROP TABLE`, …) — pass `force: true` to override — and sanitizes ESC / bracketed-paste terminators. `pty_read` neutralizes control characters in what it returns by default (`raw: true` returns the bytes verbatim). This is a **tripwire, not a sandbox** (see [Known constraints](#known-constraints-by-design-not-bugs)).
|
|
281
296
|
|
|
297
|
+
Each `pty_send` accepts at most 64 KiB of UTF-8 text. Sends to the same session are serialized across aiterm processes so chunks cannot interleave. On macOS, text is pasted through tmux in UTF-8-safe 256-byte chunks to avoid the platform PTY truncation observed with long input; Linux and WSL use one bounded paste. If a later chunk fails, aiterm reports the partial-send state and does not press Enter automatically. A lock left by a terminated sender fails closed before sending; close and recreate that session (or use `pty_kill_all` when every session is disposable) to clean it up safely.
|
|
298
|
+
|
|
282
299
|
## A human can watch
|
|
283
300
|
|
|
284
301
|
Sessions live on a shared tmux socket. The `tmux -S … attach -t <id>` line printed by `pty_open` (and by each agent launcher) lets a human attach to the same terminal and intervene (`Ctrl-b d` to detach) — including watching a launched Codex/Grok/Composer session run and taking the keyboard from your AI mid-task. On native Windows the printed line is the WSL form — `wsl tmux -S … attach -t <id>` — since the session lives inside WSL.
|
|
@@ -329,4 +346,15 @@ If aiterm let your AI hand a task to another agent — or saved you a round-trip
|
|
|
329
346
|
|
|
330
347
|
## License
|
|
331
348
|
|
|
349
|
+
> Grok OAuthのauth/lock共有は0.9.1当時の契約で、2026-07-14に廃止した。現行はmanaged隔離を維持し、検証済み通常auth正本を`GROK_AUTH_PATH`でvendorへ渡す。aitermはlock・atomic replace・copy-backを所有しない。
|
|
350
|
+
|
|
332
351
|
MIT
|
|
352
|
+
|
|
353
|
+
## Grok OAuth isolation
|
|
354
|
+
|
|
355
|
+
For `agent_done`, Grok/Composer keep launch-local `GROK_HOME` and fake `HOME`.
|
|
356
|
+
The child receives `GROK_AUTH_PATH` pointing at the validated normal auth
|
|
357
|
+
canonical file; managed homes never contain auth or lock symlinks/copies.
|
|
358
|
+
aiterm does not create locks or copy credentials back. An inherited
|
|
359
|
+
`GROK_AUTH_PATH` must be absolute and safe; only an absent default auth file is
|
|
360
|
+
allowed when `XAI_API_KEY` is set.
|