gate4agent 0.4.5

Transport library for CLI AI agents — first tier: Claude Code, Codex, Kimi, Grok. Pipe, PTY, ACP (Agent Client Protocol), and Daemon transports.
Documentation

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-native call 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 gate4agent::{CliTool, SessionConfig, AgentEvent, PipeSession, PipeProcessOptions};

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let config = SessionConfig {
        tool: CliTool::ClaudeCode,
        working_dir: std::env::current_dir()?,
        env_vars: vec![],
        name: None,
    };
    let session = PipeSession::spawn(config, "Say hello in 3 words", PipeProcessOptions::default()).await?;

    let mut rx = session.subscribe();
    while let Ok(event) = rx.recv().await {
        match event {
            AgentEvent::Text { text, .. } => print!("{text}"),
            AgentEvent::SessionEnd { .. } => break,
            _ => {}
        }
    }
    Ok(())
}

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 --settings network 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 rusqlite dependency is gone, so the transport core no longer pins libsqlite3-sys against consumers on rusqlite 0.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-pty fork is replaced by the in-house gate4agent-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, AgentEvent renamed, PipeSession removed, OpenClaw fantasy transport
  • 0.2.1 — cleanup: OpenClaw removed (was never functional), PipeSession restored for 0.1.x compatibility, TransportSession is now a thin router over PipeSession
  • 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-auto replaces removed --ask-for-approval)
  • 0.2.5 — live integration tests: fixed Codex flags, OpenCode run subcommand, Gemini -p flag, Windows cmd /C quoting; 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.node is 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_item with role=user), old .json session format removed (no cwd field = leaked into all projects).
  • 0.2.25–0.2.28 — CliCapabilities API: ModelInfo, PermissionModeInfo, CliFeatures per CLI tool. Gemini --model flag 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, OpenCode opencode.json). Model picker enrichment at runtime.
  • 0.2.30 — Probe + Context tracking: probe_all() discovers installed CLIs with caching (~/.gate4agent/probe-cache.json). ContextTracker accumulates tokens per session, computes remaining context. Extended TurnComplete with cache_read_tokens, cache_write_tokens, reasoning_tokens, context_window, is_cumulative. Codex event_msg/token_count parser (cumulative totals + model_context_window). Claude/Gemini/OpenCode parsers extract cache and reasoning tokens. Fixed Claude model IDs (4 → 4.6). Removed image_to_prompt_reference() and PipeSession::tool().
  • 0.2.31 — ContextTracker wired into runtime: AgentInstance now holds a ContextTracker, updated on every TurnComplete event. AgentRenderSnapshot gains context_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/haiku alias entries from Claude.
  • 0.2.36 — feat: cure runs lazily on first history load or session start. ensure_cure_once() populates ~/.gate4agent/models.json from OpenCode cache before tool.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, so context_percent shows 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. Codex event_msg normalizes input_tokens by subtracting cached_input_tokens to avoid double-counting. New cure module: runtime model discovery from OpenCode disk cache (~/.cache/opencode/models.json) with optional OpenRouter fallback (cure-network feature). 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 ContextTracker from model capabilities at SessionStart (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::OpenClaw no longer exists. If you matched on it, delete that arm. OpenClaw was never functional (unverified daemon protocol, fictional acpx API surface).
  • PipeSession restored — 0.1.x callers that used PipeSession::spawn(config, prompt, options) compile again. The PipeSession now includes SessionEnd synthesis (previously only in the 0.2.0 pipe_runner).
  • TransportSession is now a thin wrapper over PipeSession. Its public API (spawn, subscribe, session_id, send_prompt, kill) is unchanged. Internal: no more TransportHandle enum, no dead Pty variant.
  • DaemonNotRunning / DaemonProbeTimeout error variants removed — they were only reachable via OpenClaw. Remove any match arms for these.

0.2.18 → 0.2.19

  • RpcSession removed — if you were using gate4agent::rpc::RpcSession or the top-level gate4agent::RpcSession / RpcSessionOptions / RpcSessionError re-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 rpc primitives unchanged — RpcRequest, RpcResponse, RpcError, RpcNotification, RpcId, HostHandler, MethodRouter, RejectAllHandler, PendingRequests, IdGen, classify_line are all still exported. Only the RpcSession transport struct is gone.

0.1.x → 0.2.1

  1. Events: AgentEvent::Pipe* → neutral names. Rename all match arms:

    • PipeText → Text
    • PipeToolStart → ToolStart
    • PipeToolResult → ToolResult
    • PipeThinking → Thinking
    • PipeTurnComplete → TurnComplete
    • PipeSessionStart → SessionStart
    • PipeSessionEnd → SessionEnd
  2. PipeSession::spawn — signature unchanged: PipeSession::spawn(config, prompt, options). Compiles directly.

  3. SpawnOptions: new unified struct. Fields: working_dir, prompt, resume_session_id, model, append_system_prompt, extra_args, env_vars.

  4. CliTool is 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