gate4agent
gate4agent is a library that drives CLI coding agents — Claude Code, Codex,
Kimi, Grok — over PTY, pipe, ACP, and daemon transports behind one API:
spawn, stream, resume; see Transport core below. On top
of that transport core it also carries the session runtime a node embeds to
run those agents as managed sessions: an adapter/tool catalog, a session
kernel, the native runtime, and per-CLI process hooks and history readers.
The node/c2/harness/TUI stack that used to live in this repository is now
hatchery, built on this library.
Provider tiers
| Provider | Tier | Support path |
|---|---|---|
| Claude Code | first tier | full workbench: PTY sessions, native history, hooks, spawn/observe through node → harness; transport core verified on 2.1.224 |
| Codex CLI | first tier | full workbench; transport core verified on 0.144.6 |
| Kimi Code | first tier | full workbench via the adapter registry; current transport-core PTY canary is failing (see the matrix below) |
| Grok CLI | first tier | full workbench via the adapter registry (gate4agent-adapters): PTY sessions, native history (~/.grok/sessions), hooks; a resume gap is tracked |
| qwen-code | wired, unverified | adapter registry entry exists; no verification claim |
| Gemini, OpenCode | legacy | transport-core paths last live-verified in the 0.2.5–0.2.6 era; outside the product target |
Repository layout
The root src/ tree is the transport core — spawning, streaming,
resuming, and owning interactive CLI-agent subprocesses through one API,
published as the gate4agent crate. See Source layout
below for its internal module structure.
crates/ holds the session runtime that a node embeds on top of the
transport core, plus the in-house PTY backend:
gate4agent-pty— the in-house PTY backend (std-only, zero external PTY dependencies: Windows ConPTY + a unix macOS/Linux backend).gate4agent-types— shared wire/data types.gate4agent-adapters— the adapter registry (Grok, qwen-code, and other CLIs wired outside the transport core's own pipe/PTY clients).gate4agent-catalog— the CLI interop reference registry.gate4agent-engine,gate4agent-kernel,gate4agent-handle— the session runtime substrate:catalog→kernel→runtime-nativecall down into the root crate's transports.gate4agent-tool-protocol,gate4agent-tool-engine— tool-call wire types and execution.gate4agent-shell-history,-shell-capabilities,-shell-hooks,-shell-managed-hooks,-shell-one-shot,-shell-native— per-CLI shell integration: history readers, capability probing, hook wiring.gate4agent-runtime-native— the native runtime a node embeds to run a managed session end to end.gate4agent-provider-ports— the provider-facing port/trait boundary.gate4agent-testkit— authentication-free provider fixtures and the Windows headless test supervisor (windows-headless-supervisor).g4a— a placeholder crate reserving the crates.io name.
All new development happens in crates/; the root library changes only
when the transport core itself does.
Tests
Windows PTY/session-touching tests run only through the headless test
supervisor (gate4agent-testkit's windows-headless-supervisor binary) — it
suppresses Windows fault dialogs and enforces a hard per-test timeout that
plain cargo test cannot:
target\release\windows-headless-supervisor.exe <timeout_ms> <ABS path to test exe> --exact <test_fn>
All builds share the workspace's own target/. A per-run --target-dir is
a full copy of the dependency build and they pile up fast; when two builds
overlap, Cargo's build lock simply makes the second wait. Tests gated by
require_windows_headless_supervisor_for_test() reject themselves outright if
run any other way.
Transport core
The root gate4agent crate is a standalone Rust library for spawning,
streaming, resuming, and owning interactive CLI-agent subprocesses through one
API — usable on its own, with no node/c2/harness in the loop.
Supported CLI tools
| Tool | Transport | Pipe mode | ACP | Resume | Notes |
|---|---|---|---|---|---|
| Claude Code | Structured inline + PTY | current stream-json |
not in default catalog | current --resume <id> |
Full native Windows PTY lifecycle verified on 2.1.224 |
| Codex CLI | Structured inline + PTY | current exec --json |
not in default catalog | current exec resume |
Inline and Windows PTY verified on 0.144.6; inline defaults to read-only |
| Kimi Code | Structured inline + raw PTY | current stream-json |
unsupported | active adapter --session <id>; legacy PipeSession -r <id> |
Version 0.31.1 exposes --session; the latest PTY canary exited before readiness with a local provider EPERM, so current PTY lifecycle is not claimed |
| Grok CLI | PTY via the adapter registry (workbench path) | — (no transport-core pipe client) | not active | resume gap tracked | First-tier through gate4agent-adapters, not this table's transport-core clients: PTY sessions, native history, hooks |
The table above is the transport core's own verified matrix. Grok and
qwen-code ride the modern adapter registry (gate4agent-adapters) used by the
node stack: Grok is a first-tier provider (a known resume gap is tracked);
qwen-code is wired but unverified. The separate agent module also carries a
33-entry reference registry of CLI interop metadata derived from the Orca
project's public tool descriptions (pinned by revision in
gate4agent-catalog; credit to Orca for the original grounding); those
entries are transitional code debt, not support claims. Gemini,
OpenCode, and the other reference entries were last live-verified in the
0.2.5–0.2.6 era and are outside the current product target.
Quick start
use ;
async
Resume an existing session with
SpawnOptions { resume_session_id: Some("abc-123-session".into()), ..opts };
each active adapter handles it in its own way (Codex exec resume, Claude
--resume <id>, Kimi --session <id>) behind that one field.
Transport classes
- Structured inline — spawn one owned vendor child, read JSONL, then create a new child with the provider session id to resume.
- PTY — own the interactive terminal process: ordered bytes, VT100 state, bounded replay, input, resize, interrupt, teardown. Never auto-accepts workspace-trust or update prompts; those stay visible for the operator.
- ACP and daemon modules are compatibility surfaces, not part of the
current product target (
acp::AcpSession,daemon::DaemonSession).
LaunchPlan (via plan_launch) always produces an executable plus an
argument vector — it never concatenates a prompt into a shell command.
prepare_input() produces bounded, UTF-8-safe writes with bracketed-paste
neutralization of embedded terminal control sequences.
Source layout
src/
├── lib.rs — library root, re-exports
├── agent/ — AgentId, registry, built-in specs, argv planner, typed input preparation
├── core/ — AgentEvent, CliTool, SessionConfig, AgentError
├── transport/ — TransportSession (thin router over PipeSession), SpawnOptions
├── pipe/ — PipeSession, per-CLI NDJSON parsers + command builders
├── pty/ — PtyWrapper, PtySession, VTE/screen parsers, per-CLI PTY parsers
├── acp/ — Agent Client Protocol transport (compatibility surface)
├── rpc/ — shared JSON-RPC 2.0 primitives, used internally by acp/
├── probe/ — probe_all(), CliProbe, cache logic
├── context/ — ContextTracker, TurnCompleteData
├── cure/ — runtime model discovery (OpenCode cache → OpenRouter → hardcoded)
├── daemon/ — DaemonSession, per-daemon adapters [skeleton, not functional]
└── history/ — per-CLI session history readers (Claude, Codex, Gemini, OpenCode)
Windows spawn strategy
Reviewed Claude, Codex, and Kimi npm installations resolve to their direct
executable or JavaScript entrypoint, so prompts stay real argv/stdin data
instead of being reparsed by a .cmd shim. Unknown legacy wrappers fall back
to a shell. Unix uses direct process execution.
Current live testing status
| Tool | Pipe | PTY | ACP | Notes |
|---|---|---|---|---|
| Claude Code 2.1.224 | fresh observed; current resume canary failed | full lifecycle verified | not active | Current PTY: initial/follow-up prompt, resize, in-flight interrupt, recovery, and teardown live-verified |
| Codex 0.144.6 | fresh/resume verified | live | not active | Initial/follow-up, resize, in-flight interrupt, recovery, cleanup |
| Kimi Code 0.31.1 | current canary exited before completion | current canary failed before readiness | unsupported | Local provider state reported EPERM; no current PTY lifecycle claim |
| Grok CLI | — (adapter-registry path, not a transport-core pipe client) | live through the workbench (node adapter registry) | not active | Live-verified in the workbench stack 2026-08-19: operator spawn/observe/stop through harness → c2 → node; resume gap tracked |
Vendor-live inline/PTY tests are opt-in (--ignored) — they need an
installed, authenticated CLI and network access. Plain cargo test is
hermetic and never touches a provider account.
Prerequisites
At least one CLI agent must be installed on the host. gate4agent does not install them.
| CLI | Install |
|---|---|
| Claude Code | npm install -g @anthropic-ai/claude-code |
| Codex | npm install -g @openai/codex |
| Kimi Code | npm install -g @moonshot-ai/kimi-code |
| Grok CLI / qwen-code | per their vendors' instructions |
Versioning
- 0.4.1 — ordinary patch bump after websession→master merge (bridge skeleton, Claude ProviderHome
--settingsnetwork overlay, dig2 station probe/lease). Same first crates.io wave crates; not published to crates.io from this tip (owner publish later). - 0.4.0 — breaking: non-fleet vendors cut (Gemini, OpenCode, Qwen
parsers, pipe builders and history readers removed); the
rusqlitedependency is gone, so the transport core no longer pinslibsqlite3-sysagainst consumers onrusqlite0.32+; the harness mailbox moved out into its own service. Same first crates.io wave:gate4agent-pty,gate4agent-types,gate4agent-adapters,gate4agent-catalog,gate4agent,g4a. - 0.3.0 — the workspace era. The repo is an agent workbench
(node / c2 / harness / TUI over the transport core), not a single-crate
library; the vendored
portable-ptyfork is replaced by the in-housegate4agent-pty(std-only, zero external PTY dependencies: Windows ConPTY + a unix macOS/Linux backend, verified on all three OSes); first crates.io wave published at 0.3.0:gate4agent-pty,gate4agent-types,gate4agent-adapters,gate4agent-catalog,gate4agent,g4a(the remaining workbench crates publish after the planned crate consolidation). - 0.1.x — original 3-CLI library (Claude, Codex, Gemini)
- 0.2.0 — breaking: 6 CLIs,
TransportSession,AgentEventrenamed,PipeSessionremoved, OpenClaw fantasy transport - 0.2.1 — cleanup: OpenClaw removed (was never functional),
PipeSessionrestored for 0.1.x compatibility,TransportSessionis now a thin router overPipeSession - 0.2.2 — parser isolation: NdjsonParser trait extracted, per-CLI parser modules split out
- 0.2.3 — source tree restructure into core/pty/pipe layout; proper pipe builders+parsers for Codex, Gemini, Cursor, OpenCode (research-based, NOT yet tested against live CLI output)
- 0.2.4 — docs update, Codex flags fixed (
--full-autoreplaces removed--ask-for-approval) - 0.2.5 — live integration tests: fixed Codex flags, OpenCode
runsubcommand, Gemini-pflag, Windowscmd /Cquoting; all parsers verified against real CLI output - 0.2.6 — Gemini + OpenCode live-verified; OpenCode parser rewritten from real CLI output
- 0.2.7 — Cursor removed (no native Windows support, broken headless mode, closed-source CLI). 4 CLI tools remain: Claude Code, Codex, Gemini, OpenCode.
- 0.2.8 — SpawnOptions extended: continue_last, allowed_tools, permission_mode, mcp_config, max_turns, sandbox. Per-CLI builders updated.
- 0.2.9 — Daemon transport skeleton: DaemonSession, DaemonConfig, DaemonType (OpenCode, OpenClaw). Not yet functional — API surface documented for future implementation.
- 0.2.10 — Bidirectional JSON-RPC 2.0 primitives: RpcRequest, RpcResponse, RpcNotification, PendingRequests, HostHandler, MethodRouter. Shared infrastructure for ACP transport.
- 0.2.11 — Critical bugfixes: stale transport_session cleared on exit, send_prompt() returns BrokenPipe instead of silent no-op, OpenCode emits SessionStart, Gemini skips non-JSON banners silently, history readers for Codex/Gemini/OpenCode
- 0.2.12 — Test coverage: Gemini parser (14 tests), Claude parser (+8), builder argv parity (22 tests), PipeSession live test. README/DEBUGGING.md fixed. Examples added.
- 0.2.13–0.2.15 — OpenCode default model, env sanitization, test cleanup, TermCell improvements
- 0.2.16 — ACP transport: full Agent Client Protocol (JSON-RPC 2.0 over stdio) implementation. AcpSession with initialize + session/new handshake, multi-turn prompt(), session/update streaming, agent→host callbacks (fs, terminal, permissions). Live-verified with Gemini, OpenCode, Claude, Codex. 199 unit tests.
- 0.2.17 — Cursor removed again (no Windows binary:
node_sqlite3.nodeis a Linux ELF, crashes on Windows with "is not a valid Win32 application"; no official Windows build exists). 4 CLI tools remain: Claude Code, Codex, Gemini, OpenCode. - 0.2.18 — ACP host handler extended: TerminalAcpHandler with real terminal execution, FilesystemAcpHandler root whitelisting.
- 0.2.19 — RpcSession removed: standalone RPC transport was a pre-ACP intermediate step, now superseded by AcpSession. Shared JSON-RPC primitives (message, pending, handler, id) retained in
rpc/for ACP internal use. - 0.2.20 — History readers: workdir scoping for Codex (cwd field), Gemini (projects.json slug), OpenCode (directory field). All readers now filter sessions by working directory.
- 0.2.21 — Docs: fixed README Quick Start example, renamed rpc_hello → acp_hello example.
- 0.2.22 — History readers: preview extraction for Codex/Gemini/OpenCode (first real user message), system message filtering (Codex injected XML/AGENTS.md content excluded).
- 0.2.23 — History readers: Codex zombie session filter (sessions with no user input excluded), OpenCode SQLite reader (reads from ~/.local/share/opencode/opencode.db instead of nonexistent ~/.opencode/).
- 0.2.24 — History readers: Codex duplicate message fix (skip
response_itemwith role=user), old.jsonsession format removed (no cwd field = leaked into all projects). - 0.2.25–0.2.28 —
CliCapabilitiesAPI:ModelInfo,PermissionModeInfo,CliFeaturesper CLI tool. Gemini--modelflag support, Codex configurable permission modes, Claude conditional--dangerously-skip-permissions. - 0.2.29 — Dynamic model discovery:
discover_capabilities()reads CLI configs (Codex~/.codex/config.toml, OpenCodeopencode.json). Model picker enrichment at runtime. - 0.2.30 — Probe + Context tracking:
probe_all()discovers installed CLIs with caching (~/.gate4agent/probe-cache.json).ContextTrackeraccumulates tokens per session, computes remaining context. ExtendedTurnCompletewithcache_read_tokens,cache_write_tokens,reasoning_tokens,context_window,is_cumulative. Codexevent_msg/token_countparser (cumulative totals +model_context_window). Claude/Gemini/OpenCode parsers extract cache and reasoning tokens. Fixed Claude model IDs (4 → 4.6). Removedimage_to_prompt_reference()andPipeSession::tool(). - 0.2.31 — ContextTracker wired into runtime:
AgentInstancenow holds aContextTracker, updated on everyTurnCompleteevent.AgentRenderSnapshotgainscontext_percent: Option<f64>— consumers get live context window usage without any extra work. - 0.2.37 — Full OpenCode model catalog + remove Claude aliases. All 49 OpenCode built-in models (12 free first, 37 paid). Removed redundant
opus/sonnet/haikualias entries from Claude. - 0.2.36 — feat: cure runs lazily on first history load or session start.
ensure_cure_once()populates~/.gate4agent/models.jsonfrom OpenCode cache beforetool.capabilities()is called, so context windows are accurate from the first interaction. - 0.2.35 — feat(history): SessionUsage from loaded sessions.
load_session_with_usage()extracts token counts from Claude JSONL history. Context tracker is initialized when loading past sessions, socontext_percentshows real values in UI instead of 0%. - 0.2.34 — fix(context): correct usage_percent formula + cure module.
used_tokens()now =input + output + cache_read + cache_write(matches OpenCode's formula). Per-turn mode: input/cache REPLACE (snapshot), output ACCUMULATES. Codexevent_msgnormalizesinput_tokensby subtractingcached_input_tokensto avoid double-counting. Newcuremodule: runtime model discovery from OpenCode disk cache (~/.cache/opencode/models.json) with optional OpenRouter fallback (cure-networkfeature). Persists to~/.gate4agent/models.json, overlays context windows onto hardcoded capabilities. - 0.2.33 — fix(capabilities): correct context windows and model IDs for all 4 CLIs — Claude Opus/Sonnet 4.6 → 1M tokens, Codex all → 272K, Gemini preview IDs fixed, OpenCode models updated to current.
- 0.2.32 — Fix context_percent always 0%: Initialize
ContextTrackerfrom model capabilities atSessionStart(matches model ID →context_window). Reset tracker on new session spawn so stale data doesn't persist across sessions.
The phased roadmap (P1–P4: one app↔harness protocol, light-harness
extraction, full node-surface relay, cowork) was for the node/c2/harness/TUI
stack and now lives in hatchery's ROADMAP.md, not here.
Migration guide
0.2.0 → 0.2.1
- OpenClaw removed —
CliTool::OpenClawno longer exists. If you matched on it, delete that arm. OpenClaw was never functional (unverified daemon protocol, fictional acpx API surface). PipeSessionrestored — 0.1.x callers that usedPipeSession::spawn(config, prompt, options)compile again. ThePipeSessionnow includes SessionEnd synthesis (previously only in the 0.2.0pipe_runner).TransportSessionis now a thin wrapper overPipeSession. Its public API (spawn,subscribe,session_id,send_prompt,kill) is unchanged. Internal: no moreTransportHandleenum, no deadPtyvariant.DaemonNotRunning/DaemonProbeTimeouterror variants removed — they were only reachable via OpenClaw. Remove any match arms for these.
0.2.18 → 0.2.19
RpcSessionremoved — if you were usinggate4agent::rpc::RpcSessionor the top-levelgate4agent::RpcSession/RpcSessionOptions/RpcSessionErrorre-exports, migrate to [AcpSession] instead. ACP does everything RpcSession did (bidirectional JSON-RPC 2.0, host handlers, multi-turn) but follows the standard Agent Client Protocol.- Shared
rpcprimitives unchanged —RpcRequest,RpcResponse,RpcError,RpcNotification,RpcId,HostHandler,MethodRouter,RejectAllHandler,PendingRequests,IdGen,classify_lineare all still exported. Only theRpcSessiontransport struct is gone.
0.1.x → 0.2.1
-
Events:
AgentEvent::Pipe*→ neutral names. Rename all match arms:PipeText→TextPipeToolStart→ToolStartPipeToolResult→ToolResultPipeThinking→ThinkingPipeTurnComplete→TurnCompletePipeSessionStart→SessionStartPipeSessionEnd→SessionEnd
-
PipeSession::spawn— signature unchanged:PipeSession::spawn(config, prompt, options). Compiles directly. -
SpawnOptions: new unified struct. Fields:working_dir,prompt,resume_session_id,model,append_system_prompt,extra_args,env_vars. -
CliToolis now non-exhaustive in effect (new variant:OpenCode). Add arms or a_ =>fallback.
Support the Project
If you find this tool useful, consider supporting development:
| Currency | Network | Address |
|---|---|---|
| USDT | TRC20 | TNxMKsvVLYViQ5X5sgCYmkzH4qjhhh5U7X |
| USDC | Arbitrum | 0xEF3B94Fe845E21371b4C4C5F2032E1f23A13Aa6e |
| ETH | Ethereum | 0xEF3B94Fe845E21371b4C4C5F2032E1f23A13Aa6e |
| BTC | Bitcoin | bc1qjgzthxja8umt5tvrp5tfcf9zeepmhn0f6mnt40 |
| SOL | Solana | DZJjmH8Cs5wEafz5Ua86wBBkurSA4xdWXa3LWnBUR94c |
License
MIT