Build your first agent
Checked against Orca Agent Engine v0.5.1
What you will build
A support-triage agent: it reads a ticket and routes it to a team. From an empty Workspace to its first reply takes five calls to the Registry. Pick one.
Connect to an engine
Every call goes to the Registry, so you need its address and a Workspace API key. The docs’ local tutorial starts an engine on your machine and leaves you with both.
ork reads the address from ORCA_REGISTRY_URL; the SDKs read ORCA_BASE_URL. A Workspace key travels in the x-api-key header, so the SDK clients set that header themselves.
CLI
LOCAL_DIR="$HOME/.ork-local"
export ORCA_REGISTRY_URL="http://127.0.0.1:8080"
export ORCA_API_KEY="$(cat "$LOCAL_DIR/secrets/workspace-api-key")"
ork api-groupsTypeScript
// npm install @runorca/orca-sdk
// Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import Orca from "@runorca/orca-sdk";
const orca = new Orca({
baseURL: process.env.ORCA_BASE_URL,
apiKey: null,
defaultHeaders: { "x-api-key": process.env.ORCA_API_KEY! },
});Python
# pip install runorca
# Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import os
from orca import Orca
client = Orca(
base_url=os.environ["ORCA_BASE_URL"],
api_key=None,
default_headers={"x-api-key": os.environ["ORCA_API_KEY"]},
)Create an environment
An environment is the template a session’s sandbox is built from. Every session names one, so it comes first. A name is all it takes.
Keep the id. The session you start in two steps passes it as environment_id.
CLI
environment=$(ork agent environments create --name "support" -o json)
ENV_ID=$(jq -r '.id' <<< "$environment")TypeScript
const environment = await orca.environments.create({ name: "support" });Python
environment = client.environments.create(name="support")Response
{
"id": "env_01H8...",
"type": "environment",
"name": "support"
}Abridged. The field names are the API reference’s.
Define the agent
An agent is a definition: a name, a model, a system prompt and the harness that runs its loop. Pick a harness, and the model and the code follow.
The harness is fixed when the agent is created. A new prompt or model makes a new version; a different harness takes a second agent.
CLI · Claude Agent SDK
agent=$(ork agent create \
--name "support-triage" \
--model claude-sonnet-4-6 \
--system "Triage each support ticket and route it to a team." \
--metadata harness=claude_agent_sdk \
-o json)
AGENT_ID=$(jq -r '.id' <<< "$agent")TypeScript · Claude Agent SDK
const agent = await orca.agents.create({
name: "support-triage",
model: "claude-sonnet-4-6",
system: "Triage each support ticket and route it to a team.",
metadata: { harness: "claude_agent_sdk" },
});Python · Claude Agent SDK
agent = client.agents.create(
name="support-triage",
model="claude-sonnet-4-6",
system="Triage each support ticket and route it to a team.",
metadata={"harness": "claude_agent_sdk"},
)CLI · Codex
agent=$(ork agent create \
--name "support-triage" \
--model gpt-5.4 \
--system "Triage each support ticket and route it to a team." \
--metadata harness=codex_sdk \
-o json)
AGENT_ID=$(jq -r '.id' <<< "$agent")TypeScript · Codex
const agent = await orca.agents.create({
name: "support-triage",
model: "gpt-5.4",
system: "Triage each support ticket and route it to a team.",
metadata: { harness: "codex_sdk" },
});Python · Codex
agent = client.agents.create(
name="support-triage",
model="gpt-5.4",
system="Triage each support ticket and route it to a team.",
metadata={"harness": "codex_sdk"},
)CLI · Pi
agent=$(ork agent create \
--name "support-triage" \
--model-json '{"provider":"anthropic","id":"claude-sonnet-4-6"}' \
--system "Triage each support ticket and route it to a team." \
--metadata harness=pi_sdk \
-o json)
AGENT_ID=$(jq -r '.id' <<< "$agent")TypeScript · Pi
const agent = await orca.agents.create({
name: "support-triage",
model: { provider: "anthropic", id: "claude-sonnet-4-6" },
system: "Triage each support ticket and route it to a team.",
metadata: { harness: "pi_sdk" },
});Python · Pi
agent = client.agents.create(
name="support-triage",
model={"provider": "anthropic", "id": "claude-sonnet-4-6"},
system="Triage each support ticket and route it to a team.",
metadata={"harness": "pi_sdk"},
)Response · Claude Agent SDK
{
"id": "agt_01H8...",
"type": "agent",
"name": "support-triage",
"version": 1,
"model": {
"id": "claude-sonnet-4-6"
},
"metadata": {
"harness": "claude_agent_sdk"
}
}Abridged. The field names are the API reference’s.
Response · Codex
{
"id": "agt_01H8...",
"type": "agent",
"name": "support-triage",
"version": 1,
"model": {
"id": "gpt-5.4"
},
"metadata": {
"harness": "codex_sdk"
}
}Abridged. The field names are the API reference’s.
Response · Pi
{
"id": "agt_01H8...",
"type": "agent",
"name": "support-triage",
"version": 1,
"model": {
"id": "claude-sonnet-4-6"
},
"metadata": {
"harness": "pi_sdk"
}
}Abridged. The field names are the API reference’s.
Start a session
A session is one run of the agent, in one environment. Creating it provisions nothing: the session starts idle, and its sandbox is acquired when the first message arrives.
Passing the agent’s id pins its latest version. Edit the agent later and this session keeps the version it started with.
CLI
session=$(ork agent sessions create \
--agent "$AGENT_ID" \
--environment-id "$ENV_ID" \
-o json)
SESSION_ID=$(jq -r '.id' <<< "$session")TypeScript
const session = await orca.sessions.create({
agent: agent.id,
environment_id: environment.id,
});Python
session = client.sessions.create(
agent=agent.id,
environment_id=environment.id,
)Response
{
"id": "ses_01H8...",
"type": "session",
"agent": {
"id": "agt_01H8...",
"type": "agent",
"version": 1,
"name": "support-triage"
},
"environment_id": "env_01H8...",
"status": "idle"
}Abridged. The field names are the API reference’s.
Send a message, read the reply
A message is an event you append to the session’s log. The agent’s work lands in the same log, so you read the reply as a stream. The turn is over when the session goes idle.
The stream starts at cursor 0, the first event. Opened with no cursor it starts from now, and a short turn can end before it attaches.
CLI
ork agent sessions events send message \
--session "$SESSION_ID" \
--text "Triage this ticket: customer cannot log in."
ork agent sessions events stream \
--session "$SESSION_ID" \
--from-cursor 0 \
--timeout 60sTypeScript
const message = "Triage this ticket: customer cannot log in.";
await orca.sessions.events.send(session.id, {
events: [
{
type: "user.message",
content: [{ type: "text", text: message }],
},
],
});
const stream = await orca.sessions.events.stream(session.id, {
from_cursor: "0",
});
for await (const event of stream) {
console.log(event.type);
if (event.type === "session.status_idle") break;
}Python
message = "Triage this ticket: customer cannot log in."
client.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [{"type": "text", "text": message}],
}
],
)
for event in client.sessions.events.stream(session.id, from_cursor="0"):
print(event.type)
if event.type == "session.status_idle":
breakResponse
- user.message Triage this ticket: customer cannot log in.
- session.status_running the turn starts
- span.model_request_start the model is called
- agent.message Routed to Identity: login is failing.
- span.model_request_end token usage
- session.status_idle stop_reason: end_turn
An illustration. Event types follow the API reference; the values are examples.
The whole program
Every step in order, in the tool and the harness you chose. Copy it and run it against your engine.
The program ends after one turn. What an application does next, from approving a tool call to coming back tomorrow, is the next guide.
CLI · Claude Agent SDK
# Paste into a shell that has ork and jq.
LOCAL_DIR="$HOME/.ork-local"
export ORCA_REGISTRY_URL="http://127.0.0.1:8080"
export ORCA_API_KEY="$(cat "$LOCAL_DIR/secrets/workspace-api-key")"
ork api-groups
environment=$(ork agent environments create --name "support" -o json)
ENV_ID=$(jq -r '.id' <<< "$environment")
agent=$(ork agent create \
--name "support-triage" \
--model claude-sonnet-4-6 \
--system "Triage each support ticket and route it to a team." \
--metadata harness=claude_agent_sdk \
-o json)
AGENT_ID=$(jq -r '.id' <<< "$agent")
session=$(ork agent sessions create \
--agent "$AGENT_ID" \
--environment-id "$ENV_ID" \
-o json)
SESSION_ID=$(jq -r '.id' <<< "$session")
ork agent sessions events send message \
--session "$SESSION_ID" \
--text "Triage this ticket: customer cannot log in."
ork agent sessions events stream \
--session "$SESSION_ID" \
--from-cursor 0 \
--timeout 60sTypeScript · Claude Agent SDK
// Save as support-triage.mts, then run: npx tsx support-triage.mts
// npm install @runorca/orca-sdk
// Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import Orca from "@runorca/orca-sdk";
const orca = new Orca({
baseURL: process.env.ORCA_BASE_URL,
apiKey: null,
defaultHeaders: { "x-api-key": process.env.ORCA_API_KEY! },
});
const environment = await orca.environments.create({ name: "support" });
const agent = await orca.agents.create({
name: "support-triage",
model: "claude-sonnet-4-6",
system: "Triage each support ticket and route it to a team.",
metadata: { harness: "claude_agent_sdk" },
});
const session = await orca.sessions.create({
agent: agent.id,
environment_id: environment.id,
});
const message = "Triage this ticket: customer cannot log in.";
await orca.sessions.events.send(session.id, {
events: [
{
type: "user.message",
content: [{ type: "text", text: message }],
},
],
});
const stream = await orca.sessions.events.stream(session.id, {
from_cursor: "0",
});
for await (const event of stream) {
console.log(event.type);
if (event.type === "session.status_idle") break;
}Python · Claude Agent SDK
# Save as support-triage.py, then run: python support-triage.py
# pip install runorca
# Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import os
from orca import Orca
client = Orca(
base_url=os.environ["ORCA_BASE_URL"],
api_key=None,
default_headers={"x-api-key": os.environ["ORCA_API_KEY"]},
)
environment = client.environments.create(name="support")
agent = client.agents.create(
name="support-triage",
model="claude-sonnet-4-6",
system="Triage each support ticket and route it to a team.",
metadata={"harness": "claude_agent_sdk"},
)
session = client.sessions.create(
agent=agent.id,
environment_id=environment.id,
)
message = "Triage this ticket: customer cannot log in."
client.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [{"type": "text", "text": message}],
}
],
)
for event in client.sessions.events.stream(session.id, from_cursor="0"):
print(event.type)
if event.type == "session.status_idle":
breakCLI · Codex
# Paste into a shell that has ork and jq.
LOCAL_DIR="$HOME/.ork-local"
export ORCA_REGISTRY_URL="http://127.0.0.1:8080"
export ORCA_API_KEY="$(cat "$LOCAL_DIR/secrets/workspace-api-key")"
ork api-groups
environment=$(ork agent environments create --name "support" -o json)
ENV_ID=$(jq -r '.id' <<< "$environment")
agent=$(ork agent create \
--name "support-triage" \
--model gpt-5.4 \
--system "Triage each support ticket and route it to a team." \
--metadata harness=codex_sdk \
-o json)
AGENT_ID=$(jq -r '.id' <<< "$agent")
session=$(ork agent sessions create \
--agent "$AGENT_ID" \
--environment-id "$ENV_ID" \
-o json)
SESSION_ID=$(jq -r '.id' <<< "$session")
ork agent sessions events send message \
--session "$SESSION_ID" \
--text "Triage this ticket: customer cannot log in."
ork agent sessions events stream \
--session "$SESSION_ID" \
--from-cursor 0 \
--timeout 60sTypeScript · Codex
// Save as support-triage.mts, then run: npx tsx support-triage.mts
// npm install @runorca/orca-sdk
// Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import Orca from "@runorca/orca-sdk";
const orca = new Orca({
baseURL: process.env.ORCA_BASE_URL,
apiKey: null,
defaultHeaders: { "x-api-key": process.env.ORCA_API_KEY! },
});
const environment = await orca.environments.create({ name: "support" });
const agent = await orca.agents.create({
name: "support-triage",
model: "gpt-5.4",
system: "Triage each support ticket and route it to a team.",
metadata: { harness: "codex_sdk" },
});
const session = await orca.sessions.create({
agent: agent.id,
environment_id: environment.id,
});
const message = "Triage this ticket: customer cannot log in.";
await orca.sessions.events.send(session.id, {
events: [
{
type: "user.message",
content: [{ type: "text", text: message }],
},
],
});
const stream = await orca.sessions.events.stream(session.id, {
from_cursor: "0",
});
for await (const event of stream) {
console.log(event.type);
if (event.type === "session.status_idle") break;
}Python · Codex
# Save as support-triage.py, then run: python support-triage.py
# pip install runorca
# Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import os
from orca import Orca
client = Orca(
base_url=os.environ["ORCA_BASE_URL"],
api_key=None,
default_headers={"x-api-key": os.environ["ORCA_API_KEY"]},
)
environment = client.environments.create(name="support")
agent = client.agents.create(
name="support-triage",
model="gpt-5.4",
system="Triage each support ticket and route it to a team.",
metadata={"harness": "codex_sdk"},
)
session = client.sessions.create(
agent=agent.id,
environment_id=environment.id,
)
message = "Triage this ticket: customer cannot log in."
client.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [{"type": "text", "text": message}],
}
],
)
for event in client.sessions.events.stream(session.id, from_cursor="0"):
print(event.type)
if event.type == "session.status_idle":
breakCLI · Pi
# Paste into a shell that has ork and jq.
LOCAL_DIR="$HOME/.ork-local"
export ORCA_REGISTRY_URL="http://127.0.0.1:8080"
export ORCA_API_KEY="$(cat "$LOCAL_DIR/secrets/workspace-api-key")"
ork api-groups
environment=$(ork agent environments create --name "support" -o json)
ENV_ID=$(jq -r '.id' <<< "$environment")
agent=$(ork agent create \
--name "support-triage" \
--model-json '{"provider":"anthropic","id":"claude-sonnet-4-6"}' \
--system "Triage each support ticket and route it to a team." \
--metadata harness=pi_sdk \
-o json)
AGENT_ID=$(jq -r '.id' <<< "$agent")
session=$(ork agent sessions create \
--agent "$AGENT_ID" \
--environment-id "$ENV_ID" \
-o json)
SESSION_ID=$(jq -r '.id' <<< "$session")
ork agent sessions events send message \
--session "$SESSION_ID" \
--text "Triage this ticket: customer cannot log in."
ork agent sessions events stream \
--session "$SESSION_ID" \
--from-cursor 0 \
--timeout 60sTypeScript · Pi
// Save as support-triage.mts, then run: npx tsx support-triage.mts
// npm install @runorca/orca-sdk
// Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import Orca from "@runorca/orca-sdk";
const orca = new Orca({
baseURL: process.env.ORCA_BASE_URL,
apiKey: null,
defaultHeaders: { "x-api-key": process.env.ORCA_API_KEY! },
});
const environment = await orca.environments.create({ name: "support" });
const agent = await orca.agents.create({
name: "support-triage",
model: { provider: "anthropic", id: "claude-sonnet-4-6" },
system: "Triage each support ticket and route it to a team.",
metadata: { harness: "pi_sdk" },
});
const session = await orca.sessions.create({
agent: agent.id,
environment_id: environment.id,
});
const message = "Triage this ticket: customer cannot log in.";
await orca.sessions.events.send(session.id, {
events: [
{
type: "user.message",
content: [{ type: "text", text: message }],
},
],
});
const stream = await orca.sessions.events.stream(session.id, {
from_cursor: "0",
});
for await (const event of stream) {
console.log(event.type);
if (event.type === "session.status_idle") break;
}Python · Pi
# Save as support-triage.py, then run: python support-triage.py
# pip install runorca
# Set ORCA_BASE_URL (the engine's address) and ORCA_API_KEY first.
import os
from orca import Orca
client = Orca(
base_url=os.environ["ORCA_BASE_URL"],
api_key=None,
default_headers={"x-api-key": os.environ["ORCA_API_KEY"]},
)
environment = client.environments.create(name="support")
agent = client.agents.create(
name="support-triage",
model={"provider": "anthropic", "id": "claude-sonnet-4-6"},
system="Triage each support ticket and route it to a team.",
metadata={"harness": "pi_sdk"},
)
session = client.sessions.create(
agent=agent.id,
environment_id=environment.id,
)
message = "Triage this ticket: customer cannot log in."
client.sessions.events.send(
session.id,
events=[
{
"type": "user.message",
"content": [{"type": "text", "text": message}],
}
],
)
for event in client.sessions.events.stream(session.id, from_cursor="0"):
print(event.type)
if event.type == "session.status_idle":
break