Files
Kigi-CLI/crates/codegen/kigi-tui/docs/user-guide/15-agent-mode.md
T
ZacharyZhang-NY 6f31415ed6 §9 acceptance: grep-zero sweep — every internal x.ai/grok identifier renamed
The PRD's first acceptance gate now holds: grep -RinE '\bx\.ai\b|grok'
crates/ --include='*.rs' → 0 matches (exempt: NOTICE and third-party
license archives, README provenance, and the required 'Based on Grok
Build Open Source' attribution, now sourced from version_attribution.txt).

Wire-visible renames (both sides in this repo, changed in lockstep):
- Auth method id 'grok.com' → 'kimi-code' (AuthMethodKind::KimiCode).
- Every x.ai/* and _x.ai/* ACP ext method and meta key → kigi/* /
  _kigi/* (~200 names; grokShell → kigiShell). Session-file replay keeps
  a read-side alias for the legacy '_x.ai/session/update' method so
  existing updates.jsonl histories load; writes emit only the new name
  (both directions test-pinned).
- Agent types grok-build* → kigi* with a documented legacy-prefix alias
  at resolution time so persisted sessions keep resolving.
- ToolNamespace/BuiltinAgentName GrokBuild* → Kigi* (wire snake_case
  kigi/kigi_concise/kigi_hashline; schema regenerated); grok_build
  implementation dirs renamed to kigi*.
- x-grok-* headers → x-kigi-*, __GROK_* sentinels → __KIGI_*, themes
  grokday/groknight → kigiday/kiginight (old persisted values fall back
  to the default theme), web_fetch allowlist xAI hosts → kimi.com +
  moonshot platforms, changelog CDN → this repo, grok-build changelog
  archives deleted.
- BYOK default endpoint removed: [endpoints] api_base_url is now truly
  optional with NO default — consumers fail fast with the flag name when
  unset (no silent x.ai egress). Mock harnesses inject it explicitly.
- System-prompt identity fixed: 'released by xAI' → 'an unofficial
  community CLI for Kimi' (template + regenerated encrypted form).

Also repaired pre-existing grok-era test debt found by the sweep: the
stale trace_classify default-model pin, the grok-pager UA label test,
pty-harness stale-binary reuse and non-hermetic moonshot routing (a PTY
test could previously reach the real api.moonshot.cn), and the outdated
oauth fixture scope key.

Gates: §9 grep 0; fmt clean; workspace check/clippy 0/0 (-D warnings);
FULL cargo test --workspace: 234 suites, 21,961 passed, 0 failed;
deny advisories ok.
2026-07-18 02:48:46 -04:00

11 KiB

Agent Mode (ACP) and IDE Integration

Agent mode runs Kigi as an ACP (Agent Client Protocol) server for integration with IDEs, editors, and custom tooling. Unlike single-prompt mode (kigi -p, which prints one response and exits), agent mode keeps a persistent process running and communicates through structured JSON-RPC messages.


What is ACP?

The Agent Client Protocol (ACP) is a standard for AI agent communication. It defines how clients (IDEs, editors, custom apps) interact with AI agents through a structured JSON-RPC protocol. ACP provides:

  • Session management -- create, load, and resume conversations
  • Prompt submission -- send user messages and receive streamed responses
  • Tool visibility -- see what tools the agent is using in real time
  • Thought streams -- observe the agent's reasoning process
  • Permission handling -- approve or deny tool executions interactively

stdio transport

stdio is the primary integration mode. The agent exchanges JSON-RPC messages over stdin and stdout:

kigi agent stdio

Clients that use this mode include:

  • IDE extensions (for example, Zed, Neovim, and Emacs)
  • Custom automation tools
  • ACP client libraries

Options

These options belong to the kigi agent command and apply to every mode. Pass them before the mode name, for example kigi agent --model kigi stdio. The stdio subcommand itself takes no options.

Flag Description
-m, --model <MODEL> Set the model ID (for example, kigi).
--always-approve Auto-approve every tool execution. (Alias: --yolo.)
--reauth Run authentication before starting the agent.
--agent-profile <PATH> Load an agent profile from a file.

Server mode

Run the agent as a WebSocket server for remote clients:

kigi agent serve --bind 127.0.0.1:2419 --secret <token>

Clients connect over WebSocket and authenticate with the secret token. If you omit --secret, the agent generates a token and prints it at startup; you can also supply one through the KIGI_AGENT_SECRET environment variable. The agent persists across reconnections, so a client can disconnect and later resume in-flight work.


WebSocket relay

To reach the agent over the internet instead of the local network, run a WebSocket relay server and have the agent connect to it:

kigi agent headless --kigi-ws-url wss://your-relay.example.com/ws

The agent connects out to your relay, and your web clients connect to the same relay. This is useful for building web UIs where browsers cannot spawn local processes.


ACP protocol basics

Communication follows the JSON-RPC 2.0 format. A typical session lifecycle:

  1. Initialize -- client sends initialize with capabilities
  2. Create session -- client sends session/new with working directory
  3. Send prompts -- client sends session/prompt with user messages
  4. Receive updates -- agent sends session/update notifications with streamed content
  5. Handle permissions -- agent may request tool execution approval

Architecture

+------------------------------------------+
|           ACP Client                     |
|  (IDE, Editor, Custom Application)       |
+-------------------+----------------------+
                    | JSON-RPC over stdio
+-------------------v----------------------+
|           kigi agent stdio               |
|                                          |
|  +---------+  +---------+  +---------+   |
|  | Session |  |  Tools  |  |   MCP   |   |
|  | Manager |  | Registry|  | Servers |   |
|  +---------+  +---------+  +---------+   |
+------------------------------------------+

Streaming updates

ACP streams structured events. Each session/update notification carries a sessionUpdate field that identifies the update type:

sessionUpdate value Description
agent_message_chunk A chunk of the agent's response text.
agent_thought_chunk A chunk of the agent's internal reasoning.
tool_call A new tool invocation (title, kind, status, input).
tool_call_update A status or result update for an in-flight tool call.
plan The agent's execution plan.

Each update names its type, so a client can render distinct panels for reasoning, tool calls, and response text.


Extension methods

Beyond the base ACP protocol, Kigi defines extension methods under the x.ai/ prefix for SpaceXAI-specific functionality. These cover:

Category Prefix Examples
Filesystem x.ai/fs/* list, exists, read_file, write_file
Git x.ai/git/* status, stage, commit, diffs, discard
Git Worktree x.ai/git/worktree/* create, remove, apply, list, gc
Search x.ai/search/* fuzzy/open, fuzzy/change, content
Terminal x.ai/terminal/* create, kill, output, wait_for_exit
Session Management x.ai/session/* fork, resolve_local_for_worktree_resume
Conversation & History x.ai/* prompt_history, rewind/*, compact_conversation
Authentication x.ai/auth/* get_url, submit_code
Feedback & Telemetry x.ai/* feedback, telemetry/*

The tables here show representative methods in each category. The x.ai/* set is SpaceXAI-specific and may expand across releases, so treat it as non-exhaustive and discover the available methods from the agent's initialize response.

Notifications (agent to client)

The agent sends push notifications to clients for real-time updates:

Notification Description
x.ai/search/fuzzy/status Fuzzy search results update
x.ai/git/worktree/status Worktree creation progress
x.ai/fs_notify Filesystem change notification
x.ai/fs/index Full file index update
x.ai/fs/index/delta Incremental file index update
x.ai/session_notification Session-specific updates (diff review, retry state, auto-compact)
x.ai/session/update Session update (tool calls, content)

Session _meta options

The session/new request accepts these optional _meta fields:

Field Description
rules Extra rules appended to the system prompt.
systemPromptOverride A replacement system prompt.
agentProfile An agent profile, as a name or a JSON object.

ACP SDKs

Official SDK libraries are available for multiple languages:

Language Package
TypeScript @agentclientprotocol/sdk
Rust agent-client-protocol
Python agent-client-protocol-python
Go acp-go-sdk
Kotlin acp

Compatible clients

Client Status
Zed Supported
Neovim (CodeCompanion, avante.nvim) Supported
Emacs Supported
marimo notebook Supported
JetBrains Coming soon

Integration example: a TypeScript ACP client

import { spawn, ChildProcess } from "child_process";
import * as readline from "readline";

class KigiACPChat {
  private proc!: ChildProcess;
  private sessionId!: string;
  private rl!: readline.Interface;

  constructor(private cwd = ".") {}

  async init() {
    this.proc = spawn("kigi", ["agent", "stdio"]);
    this.rl = readline.createInterface({ input: this.proc.stdout! });

    // Initialize
    await this.request("initialize", {
      protocolVersion: 1,
      clientCapabilities: {
        fs: { readTextFile: true, writeTextFile: true },
        terminal: true,
      },
    });

    // Create session
    const { sessionId } = await this.request("session/new", {
      cwd: this.cwd,
      mcpServers: [],
    });
    this.sessionId = sessionId;
    return this;
  }

  private async request(method: string, params: any): Promise<any> {
    return new Promise((resolve) => {
      const msg = JSON.stringify({ jsonrpc: "2.0", id: 1, method, params });
      this.proc.stdin!.write(msg + "\n");

      this.rl.once("line", (line) => {
        resolve(JSON.parse(line).result || {});
      });
    });
  }

  async *streamPrompt(text: string) {
    const msg = JSON.stringify({
      jsonrpc: "2.0",
      id: 1,
      method: "session/prompt",
      params: {
        sessionId: this.sessionId,
        prompt: [{ type: "text", text }],
      },
    });
    this.proc.stdin!.write(msg + "\n");

    for await (const line of this.rl) {
      const data = JSON.parse(line);

      if (data.method === "session/update") {
        const update = data.params.update;
        yield update; // { sessionUpdate, content, title, ... }
      } else if (data.result) {
        break; // Final response
      }
    }
  }
}

// Usage
const client = await new KigiACPChat(".").init();

for await (const update of client.streamPrompt("List the files in this project")) {
  switch (update.sessionUpdate) {
    case "agent_message_chunk":
      process.stdout.write(update.content?.text || "");
      break;
    case "agent_thought_chunk":
      console.log(`\n[Thinking: ${update.content?.text}]`);
      break;
    case "tool_call":
      console.log(`\n[Tool: ${update.title}]`);
      break;
  }
}

Resources