Rust examples use the runtime-backed
SessionService path, which is the same canonical session lifecycle used by the other surfaces.Create a session
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
rkat run --model claude-sonnet-4-5 "What is the capital of France?"
{
"jsonrpc": "2.0", "id": 1,
"method": "session/create",
"params": {
"prompt": "What is the capital of France?",
"model": "claude-sonnet-4-5"
}
}
curl -X POST http://localhost:8080/sessions \
-H "Content-Type: application/json" \
-d '{"prompt": "What is the capital of France?", "model": "claude-sonnet-4-5"}'
{
"prompt": "What is the capital of France?",
"model": "claude-sonnet-4-5"
}
meerkat_run tool.async with MeerkatClient() as client:
session = await client.create_session(
"What is the capital of France?",
model="claude-sonnet-4-5",
)
print(session.text)
const client = new MeerkatClient();
await client.connect();
const session = await client.createSession("What is the capital of France?", {
model: "claude-sonnet-4-5",
});
console.log(session.text);
let result = service.create_session(CreateSessionRequest {
model: "claude-sonnet-4-5".into(),
prompt: "What is the capital of France?".into(),
system_prompt: None,
max_tokens: None,
event_tx: None,
skill_references: None,
initial_turn: InitialTurnPolicy::RunImmediately,
build: None,
labels: None,
}).await?;
println!("{}", result.text);
Multi-turn
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
# Resume the most recent session
rkat resume last "Now explain it in more detail"
# Or use the shortcut
rkat continue "Now explain it in more detail"
{
"jsonrpc": "2.0", "id": 2,
"method": "turn/start",
"params": {
"session_id": "01936f8a-7b2c-7000-8000-000000000001",
"prompt": "Now explain it in more detail"
}
}
curl -X POST http://localhost:8080/sessions/01936f8a-7b2c-7000-8000-000000000001/messages \
-H "Content-Type: application/json" \
-d '{
"session_id": "01936f8a-7b2c-7000-8000-000000000001",
"prompt": "Now explain it in more detail"
}'
{
"name": "meerkat_resume",
"arguments": {
"session_id": "01936f8a-...",
"prompt": "What's my name?"
}
}
result = await session.turn("Now explain it in more detail")
print(result.text)
const result = await session.turn("Now explain it in more detail");
console.log(result.text);
let result = service.start_turn(&session_id, StartTurnRequest {
prompt: "Now explain it in more detail".into(),
system_prompt: None,
render_metadata: None,
handling_mode: HandlingMode::Queue,
event_tx: None,
skill_references: None,
flow_tool_overlay: None,
additional_instructions: None,
}).await?;
println!("{}", result.text);
Resume by ID or alias
CLI supports short prefix matching and relative aliases for resuming sessions.# Full UUID
rkat resume 01936f8a-7b2c-7000-8000-000000000001 "Keep going"
# Short prefix (git-style, fails on ambiguity)
rkat resume 019c8b99 "Keep going"
# Most recent session
rkat resume last "Keep going"
# 2nd most recent
rkat resume ~2 "Go back to this one"
# Shortcut for `resume last`
rkat c "Keep going"
List sessions
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
rkat sessions list
rkat sessions list --limit 10
rkat sessions list --limit 10 --offset 20
{"jsonrpc": "2.0", "id": 3, "method": "session/list"}
curl http://localhost:8080/sessions
{"name": "meerkat_sessions", "arguments": {}}
sessions = await client.list_sessions()
for s in sessions:
print(s.session_id, s.message_count, s.is_active)
const sessions = await client.listSessions();
for (const s of sessions) {
console.log(s.sessionId, s.messageCount, s.isActive);
}
let sessions = service.list(SessionQuery::default()).await?;
for s in &sessions { println!("{}: {}", s.session_id, s.message_count); }
Read session state
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
rkat sessions show 01936f8a-...
{
"jsonrpc": "2.0", "id": 4,
"method": "session/read",
"params": { "session_id": "01936f8a-..." }
}
curl http://localhost:8080/sessions/01936f8a-...
{"name": "meerkat_read", "arguments": {"session_id": "01936f8a-..."}}
state = await client.read_session("01936f8a-...")
print(state)
const state = await client.readSession("01936f8a-...");
console.log(state);
let view = service.read(&session_id).await?;
println!("Messages: {}", view.state.message_count);
Archive a session
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
rkat sessions delete 01936f8a-...
{
"jsonrpc": "2.0", "id": 5,
"method": "session/archive",
"params": { "session_id": "01936f8a-..." }
}
curl -X DELETE http://localhost:8080/sessions/01936f8a-...
{"name": "meerkat_archive", "arguments": {"session_id": "01936f8a-..."}}
await session.archive()
await session.archive();
service.archive(&session_id).await?;
Interrupt a turn
Cancel an in-flight turn. No-op if the session is idle.- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
rkat sessions interrupt 01936f8a-...
{
"jsonrpc": "2.0", "id": 6,
"method": "turn/interrupt",
"params": { "session_id": "01936f8a-..." }
}
curl -X POST http://localhost:8080/sessions/01936f8a-.../interrupt
{"name": "meerkat_interrupt", "arguments": {"session_id": "01936f8a-..."}}
await session.interrupt()
await session.interrupt();
service.interrupt(&session_id).await?;
Event streaming
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
# Basic streaming
rkat run --stream "Tell me a story"
# Stream view modes
rkat run --stream --stream-view primary "Plan the release"
rkat run --stream --stream-view mux "Plan the release"
rkat run --stream --stream-view focus --stream-focus mob:planner "Draft steps"
# Short flags
rkat run -s -w mux "Plan the release"
Events arrive as
session/event notifications during a turn:{
"jsonrpc": "2.0",
"method": "session/event",
"params": {
"session_id": "01936f8a-...",
"event": {
"type": "text_delta",
"delta": "The capital"
}
}
}
# SSE stream (connect before starting a turn)
curl -N http://localhost:8080/sessions/01936f8a-.../events
text_delta, tool_call_requested, turn_completed, and done.{
"name": "meerkat_run",
"arguments": {
"prompt": "Tell me a story",
"stream": true
}
}
stream: true, the MCP server sends progress notifications with AgentEvent payloads during execution.For long-running or autonomous sessions, use the managed event stream tools instead:// Open a stream
{"name": "meerkat_event_stream_open", "arguments": {"session_id": "01936f8a-..."}}
// => {"stream_id": "evt-..."}
// Poll for events (blocks until next event or timeout)
{"name": "meerkat_event_stream_read", "arguments": {"stream_id": "evt-..."}}
// Close when done
{"name": "meerkat_event_stream_close", "arguments": {"stream_id": "evt-..."}}
# Streaming on session create
async with client.create_session_streaming("Tell me a story") as stream:
async for event in stream:
match event:
case TextDelta(delta=chunk):
print(chunk, end="", flush=True)
result = stream.result
# Streaming on a follow-up turn
async with session.stream("Continue the story") as events:
async for event in events:
match event:
case TextDelta(delta=chunk):
print(chunk, end="", flush=True)
// Streaming on session create
const stream = client.createSessionStreaming("Tell me a story");
for await (const event of stream) {
if (event.type === "text_delta") {
process.stdout.write(event.delta);
}
}
const result = stream.result;
// Streaming on a follow-up turn
for await (const event of session.stream("Continue the story")) {
if (event.type === "text_delta") {
process.stdout.write(event.delta);
}
}
let (tx, mut rx) = mpsc::channel::<AgentEvent>(100);
tokio::spawn(async move {
while let Some(event) = rx.recv().await {
match event {
AgentEvent::TextDelta { delta } => print!("{}", delta),
AgentEvent::TurnCompleted { usage, .. } => {
println!("\n[Tokens: {}]", usage.total_tokens());
}
_ => {}
}
}
});
let result = agent.run_with_events("Tell me a story".into(), tx).await?;
Model and provider selection
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
rkat run --model gpt-5.2 --provider openai "Hello"
rkat run --model gemini-3-flash-preview --provider gemini "Hello"
rkat run --model claude-opus-4-6 "Hello"
{
"jsonrpc": "2.0", "id": 7,
"method": "session/create",
"params": {
"prompt": "Hello",
"model": "gpt-5.2",
"provider": "openai",
"provider_params": { "reasoning_effort": "high" }
}
}
curl -X POST http://localhost:8080/sessions \
-H "Content-Type: application/json" \
-d '{"prompt":"Explain monads","model":"gpt-5.2","provider":"openai","provider_params":{"temperature":0.7}}'
{
"prompt": "Hello",
"model": "gpt-5.2",
"provider": "openai"
}
meerkat_run tool.session = await client.create_session(
"Hello",
model="gpt-5.2",
provider="openai",
provider_params={"reasoning_effort": "high"},
)
const session = await client.createSession("Hello", {
model: "gpt-5.2",
provider: "openai",
providerParams: { reasoning_effort: "high" },
});
let result = service.create_session(CreateSessionRequest {
model: "gpt-5.2".into(),
prompt: "Explain monads".into(),
system_prompt: None,
max_tokens: None,
event_tx: None,
skill_references: None,
initial_turn: InitialTurnPolicy::RunImmediately,
build: Some(SessionBuildOptions {
provider: Some(Provider::OpenAi),
provider_params: Some(json!({"temperature": 0.7})),
..Default::default()
}),
labels: None,
}).await?;
Config management
- CLI
- JSON-RPC
- REST
- MCP
- Python
- TypeScript
- Rust
# Read config
rkat config get
rkat config get --format json --with-generation
# Replace config
rkat config set --json '{"agent": {"model": "gpt-5.2"}}'
# Merge-patch with optimistic concurrency
rkat config patch --json '{"budget": {"max_tokens": 50000}}' --expected-generation 3
{"jsonrpc": "2.0", "id": 8, "method": "config/get"}
{
"jsonrpc": "2.0", "id": 9,
"method": "config/set",
"params": {
"config": {"agent": {"model": "gpt-5.2"}},
"expected_generation": 3
}
}
{
"jsonrpc": "2.0", "id": 10,
"method": "config/patch",
"params": {
"patch": {"agent": {"max_tokens_per_turn": 8192}},
"expected_generation": 4
}
}
# Read
curl http://localhost:8080/config
# Replace
curl -X PUT http://localhost:8080/config \
-H "Content-Type: application/json" \
-d '{"config": {"agent": {"model": "gpt-5.2"}}, "expected_generation": 3}'
# Merge-patch
curl -X PATCH http://localhost:8080/config \
-H "Content-Type: application/json" \
-d '{"patch": {"agent": {"max_tokens_per_turn": 8192}}, "expected_generation": 4}'
// Get config
{"name": "meerkat_config", "arguments": {"action": "get"}}
// Patch config
{"name": "meerkat_config", "arguments": {
"action": "patch",
"patch": {"agent": {"max_tokens_per_turn": 8192}}
}}
config = await client.get_config()
await client.set_config({"agent": {"model": "gpt-5.2"}}, expected_generation=3)
await client.patch_config({"agent": {"max_tokens_per_turn": 8192}}, expected_generation=4)
const config = await client.getConfig();
await client.setConfig({ agent: { model: "gpt-5.2" } }, { expectedGeneration: 3 });
await client.patchConfig({ agent: { maxTokensPerTurn: 8192 } }, { expectedGeneration: 4 });
let store = FileConfigStore::new(config_path)?;
let envelope = store.load()?;
println!("generation: {}", envelope.generation);
store.commit(ConfigSnapshot {
config: new_config,
expected_generation: Some(envelope.generation),
})?;
Realm selection
Realms scope sessions and config. Surfaces that share arealm_id see the same state. Realm is set at startup for server surfaces (RPC, REST, MCP) and per-command or per-connection for CLI and SDKs.
- CLI
- JSON-RPC server
- REST server
- MCP server
- Python
- TypeScript
rkat --realm team-alpha run "Plan release"
rkat --realm team-alpha --instance worker-1 sessions list
rkat --realm team-alpha --realm-backend sqlite resume last "Continue"
rkat-rpc --realm team-alpha --instance worker-1
rkat-rpc --realm team-alpha --realm-backend sqlite --state-root /data/meerkat
rkat-rest --realm team-alpha --instance api-1
rkat-rest --realm team-alpha --realm-backend sqlite --state-root /data/meerkat
rkat-mcp --realm team-alpha --instance mcp-1
rkat-mcp --realm team-alpha --realm-backend sqlite --state-root /data/meerkat
await client.connect(realm_id="team-alpha", instance_id="worker-1")
await client.connect({ realmId: "team-alpha", instanceId: "worker-1" });
