Documentation Index
Fetch the complete documentation index at: https://docs.rkat.ai/llms.txt
Use this file to discover all available pages before exploring further.
For the full guide, see Structured output.
This page works best after Examples: Sessions. Start there if you have not already seen the basic create/turn/result flow.
Provide an output_schema and the agent will extract validated JSON after the agentic loop completes.
CLI
JSON-RPC
REST
MCP
Python
TypeScript
Rust
rkat run --schema '{
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["city", "country", "population"]
}' "Tell me about Tokyo"
{
"jsonrpc": "2.0", "id": 1,
"method": "session/create",
"params": {
"prompt": "Tell me about Tokyo",
"output_schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["city", "country", "population"]
}
}
}
curl -X POST http://localhost:8080/sessions \
-H "Content-Type: application/json" \
-d '{
"prompt": "Tell me about Tokyo",
"output_schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["city", "country", "population"]
}
}'
{
"prompt": "Tell me about Tokyo",
"output_schema": {
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["city", "country", "population"]
}
}
Called via the meerkat_run tool.session = await client.create_session(
"Tell me about Tokyo",
output_schema={
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"},
},
"required": ["city", "country", "population"],
},
)
print(session.structured_output)
const session = await client.createSession("Tell me about Tokyo", {
outputSchema: {
type: "object",
properties: {
city: { type: "string" },
country: { type: "string" },
population: { type: "integer" },
},
required: ["city", "country", "population"],
},
});
console.log(session.structuredOutput);
let schema = OutputSchema::new(json!({
"type": "object",
"properties": {
"city": {"type": "string"},
"country": {"type": "string"},
"population": {"type": "integer"}
},
"required": ["city", "country", "population"]
}))?;
let result = service.create_session(CreateSessionRequest {
model: "claude-sonnet-4-6".into(),
prompt: "Tell me about Tokyo".into(),
render_metadata: None,
system_prompt: None,
max_tokens: None,
event_tx: None,
skill_references: None,
initial_turn: InitialTurnPolicy::RunImmediately,
deferred_prompt_policy: DeferredPromptPolicy::Discard,
build: Some(SessionBuildOptions {
output_schema: Some(schema),
..Default::default()
}),
labels: None,
}).await?;
println!("{:?}", result.structured_output);
Next step
Schema from file
The CLI can load a schema from a JSON file instead of inline.
rkat run --schema ./schemas/city.json "Tell me about Tokyo"
The CLI detects files by checking if the value is an existing path. The file can contain a raw JSON Schema or the wrapper format with explicit name, strict, compat, and format fields.
Retries
When validation fails, the agent retries the extraction turn with error feedback. The default is 2 retries (3 total attempts).
CLI
JSON-RPC
REST
MCP
Python
TypeScript
Rust
rkat run --schema ./schema.json "Extract entities"
{
"jsonrpc": "2.0", "id": 2,
"method": "session/create",
"params": {
"prompt": "Extract entities",
"output_schema": {"type": "object", "properties": {"entities": {"type": "array"}}},
"structured_output_retries": 5
}
}
curl -X POST http://localhost:8080/sessions \
-H "Content-Type: application/json" \
-d '{
"prompt": "Extract entities",
"output_schema": {
"type": "object",
"properties": {"entities": {"type": "array"}},
"required": ["entities"]
},
"structured_output_retries": 5
}'
{
"prompt": "Extract entities",
"output_schema": {
"type": "object",
"properties": {"entities": {"type": "array"}},
"required": ["entities"]
},
"structured_output_retries": 5
}
Called via the meerkat_run tool.session = await client.create_session(
"Extract entities",
output_schema={"type": "object", "properties": {"entities": {"type": "array"}}},
structured_output_retries=5,
)
const session = await client.createSession("Extract entities", {
outputSchema: { type: "object", properties: { entities: { type: "array" } } },
structuredOutputRetries: 5,
});
let result = service.create_session(CreateSessionRequest {
model: "claude-sonnet-4-6".into(),
prompt: "Extract entities".into(),
render_metadata: None,
system_prompt: None,
max_tokens: None,
event_tx: None,
skill_references: None,
initial_turn: InitialTurnPolicy::RunImmediately,
deferred_prompt_policy: DeferredPromptPolicy::Discard,
build: Some(SessionBuildOptions {
output_schema: Some(schema),
structured_output_retries: 5,
..Default::default()
}),
labels: None,
}).await?;
Compatibility mode
Schemas are normalized across providers. The compat setting controls how unsupported JSON Schema features are handled during provider-specific lowering.
# Lossy (default): unsupported features are dropped with warnings
rkat run --schema ./schema.json "Extract data"
# For explicit `compat` control, use a wrapper schema file or a non-CLI surface
| Mode | Behavior |
|---|
lossy | Best-effort lowering; unsupported features are dropped with warnings |
strict | Reject schemas with unsupported features for the target provider |
Warnings are included in the response as schema_warnings. The same schema works with Anthropic, OpenAI, and Gemini — provider-specific lowering is handled transparently.
Read the result
The structured output appears in the response alongside the raw text.
CLI
JSON-RPC
REST
MCP
Python
TypeScript
Rust
# --output json returns the full result including structured_output
rkat run --output json --schema '{"type":"object","properties":{"answer":{"type":"string"}},"required":["answer"]}' "What is 2+2?"
# stdout: {"session_id":"...","text":"...","structured_output":{"answer":"4"}}
{
"jsonrpc": "2.0", "id": 1,
"result": {
"session_id": "01936f8a-...",
"text": "{\"city\":\"Tokyo\",\"country\":\"Japan\",\"population\":13960000}",
"structured_output": {
"city": "Tokyo",
"country": "Japan",
"population": 13960000
},
"schema_warnings": [],
"turns": 2,
"tool_calls": 0,
"usage": {"input_tokens": 120, "output_tokens": 45, "total_tokens": 165}
}
}
{
"session_id": "01936f8a-...",
"text": "{\"city\":\"Tokyo\",\"country\":\"Japan\",\"population\":13960000}",
"structured_output": {
"city": "Tokyo",
"country": "Japan",
"population": 13960000
},
"schema_warnings": [],
"turns": 2,
"tool_calls": 0,
"usage": {"input_tokens": 120, "output_tokens": 45, "total_tokens": 165}
}
// meerkat_run response includes structured_output in the tool result
{
"content": [{"type": "text", "text": "{\"session_id\":\"...\",\"structured_output\":{\"answer\":\"4\"}}"}]
}
session = await client.create_session("Tell me about Tokyo", output_schema=schema)
data = session.structured_output # dict: {"city": "Tokyo", "country": "Japan", ...}
print(data["city"])
print(data["population"])
const session = await client.createSession("Tell me about Tokyo", { outputSchema: schema });
const data = session.structuredOutput; // { city: "Tokyo", country: "Japan", ... }
console.log(data.city);
console.log(data.population);
let result = service.create_session(req).await?;
if let Some(output) = &result.structured_output {
let city = output["city"].as_str().unwrap_or_default();
let pop = output["population"].as_i64().unwrap_or_default();
println!("{}: {}", city, pop);
}
if let Some(warnings) = &result.schema_warnings {
for w in warnings {
eprintln!("{:?} at {}: {}", w.provider, w.path, w.message);
}
}