Client-Server
Agentick provides a client SDK for connecting to a running gateway from browser or Node.js.
Server Setup
import express from "express";
import { createGateway } from "@agentick/gateway";
import { createExpressMiddleware } from "@agentick/express";
const gateway = createGateway({ app: myAgent });
const server = express();
server.use("/api", createExpressMiddleware({ gateway }));
server.listen(3000);Client Usage
import { createClient } from "@agentick/client";
const client = createClient({
url: "http://localhost:3000/api",
});
// Create or join a session
const session = client.session("my-session-id");
// Send a message and stream the response
for await (const chunk of session.send("Hello!")) {
process.stdout.write(chunk.text ?? "");
}Dispatching Tools
The session accessor supports dispatch for invoking any registered tool by name without model involvement:
const session = client.session("my-session-id");
// Invoke any tool — regular or audience: "user"
const result = await session.dispatch("add-dir", { path: "/tmp/data" });This is used by TUI slash commands and client-side actions. It works on all tools — the most common pattern is dispatching audience: "user" tools (hidden from model), but regular tools are equally dispatchable.
React Integration
useChat is the all-in-one hook — messages, input steering, and tool confirmations. It auto-subscribes to the SSE transport.
import { AgentickProvider, useChat, useStreamingText } from "@agentick/react";
function Chat() {
const { messages, chatMode, submit, respondToConfirmation, toolConfirmation, lastSubmitted } =
useChat({ sessionId: "my-session" });
const { text: streamingText, isStreaming } = useStreamingText();
const [input, setInput] = useState("");
return (
<div>
{messages.map((msg) => (
<div key={msg.id} className={msg.role}>
{typeof msg.content === "string" ? msg.content : "..."}
</div>
))}
{isStreaming && <div className="assistant">{streamingText}</div>}
{toolConfirmation && (
<div>
<p>Allow {toolConfirmation.request.name}?</p>
<button onClick={() => respondToConfirmation({ approved: true })}>Allow</button>
<button onClick={() => respondToConfirmation({ approved: false })}>Deny</button>
</div>
)}
<input
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={(e) => {
if (e.key === "Enter" && input.trim()) {
submit(input);
setInput("");
}
}}
/>
</div>
);
}
function App() {
return (
<AgentickProvider clientConfig={{ baseUrl: "/api" }}>
<Chat />
</AgentickProvider>
);
}For finer control, compose individual primitives: useMessages, useToolConfirmations, useMessageSteering. See the @agentick/react README for the full hook reference.
Terminal UI
@agentick/tui is a terminal client built on the same @agentick/client and @agentick/react hooks. It connects to agents locally or over HTTP/SSE, with a pluggable UI — swap the interface by passing any Ink component:
import { createTUI } from "@agentick/tui";
// Default chat UI
createTUI({ url: "http://localhost:3000/api" }).start();
// Custom dashboard UI
createTUI({ url: "http://localhost:3000/api", ui: MyDashboard }).start();Or from the CLI:
agentick-tui --url http://localhost:3000/api --ui ./dashboard.tsxSee the Terminal UI guide for details.
Transport
The client-server communication supports multiple transports:
- SSE/HTTP — Server-Sent Events for streaming + HTTP POST for sending. Default for browser clients.
- WebSocket — Bidirectional real-time via
createWSTransport. Browser and Node.js. - Unix Socket — NDJSON over Unix domain socket via
createUnixSocketClientTransport. Node.js only. Used for daemon mode where the gateway runs as a background process and TUI clients connect locally. - Local — In-process bridge via
createLocalTransport. No network overhead.
The transport is abstracted — the client API is the same regardless of the underlying transport. The TUI, React web apps, and custom Node.js clients all use the same ClientTransport interface.
WebSocket and Unix socket transports are built on createRPCTransport (from @agentick/shared), a shared factory that provides all protocol machinery. Each transport is a thin delegate (~120 lines) providing wire-specific I/O.
Protocol Plugins
In addition to agentick's native protocol, the gateway ships two plugins that expose sessions via standard interfaces. Any client that speaks MCP or OpenAI can connect — no agentick SDK required.
MCP Server
Exposes session tools as standard MCP tools/list + tools/call via Streamable HTTP:
import { mcpServerPlugin } from "@agentick/gateway";
gateway.use(
mcpServerPlugin({
sessionId: "default",
path: "/mcp",
include: ["search", "read_file"], // optional filter
}),
);Any MCP client (Claude Desktop, Cursor, etc.) can connect at http://host:port/mcp.
OpenAI-Compatible
Serves POST /v1/chat/completions and GET /v1/models. Any OpenAI SDK client can point at the gateway:
import { openaiCompatPlugin } from "@agentick/gateway";
gateway.use(
openaiCompatPlugin({
pathPrefix: "/v1",
modelMapping: { "gpt-4o": "coding" }, // optional model→app routing
}),
);from openai import OpenAI
client = OpenAI(base_url="http://localhost:18789/v1", api_key="test")
for chunk in client.chat.completions.create(
model="default",
messages=[{"role": "user", "content": "hello"}],
stream=True,
):
print(chunk.choices[0].delta.content or "", end="")Both streaming and non-streaming responses are supported. Gateway apps appear as models in /v1/models. Sessions are keyed by the x-session-id header or auto-generated per request.