> ## Documentation Index
> Fetch the complete documentation index at: https://openrewardstandard.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Protocol Overview

> Understanding the ORS HTTP protocol

The Open Reward Standard is an **HTTP-based protocol** for connecting language model agents to reinforcement learning environments. It uses standard REST endpoints for control operations and Server-Sent Events (SSE) for delivering tool outputs.

## Design Principles

### 1. Language-Agnostic

ORS uses HTTP, making it implementable in any programming language:

* Python, TypeScript, Go, Rust, Java, etc.
* Any web framework or HTTP library
* Standard REST patterns

### 2. Episode-Centric

The protocol is organized around RL episodes (sessions):

* One session = one episode
* Episode continues until `finished: true`
* Stateful interaction across multiple tool calls

### 3. Tool-Based Interaction

All agent actions are tool calls:

* Discovered via `GET /{env_name}/tools`
* Executed via `POST /{env_name}/call`
* Return structured outputs with rewards

## Protocol Architecture

<Frame>
  <img src="https://mintcdn.com/openreward-b5106aac/9Bgqee-odFsMx4rl/images/protocol-architecture.svg?fit=max&auto=format&n=9Bgqee-odFsMx4rl&q=85&s=de544b814c50d7c4c554ed3bfaeb265e" alt="ORS Protocol Architecture — Agent communicating with ORS Server and Environment Logic" width="720" height="380" data-path="images/protocol-architecture.svg" />
</Frame>

### Key Components

**Agent Side**:

* Makes HTTP requests
* Parses SSE responses
* Maintains session ID

**ORS Server**:

* Implements HTTP endpoints
* Manages episode state
* Executes tools and returns rewards

## Episode Lifecycle

An episode (session) follows this lifecycle:

```
1. Create Session
   ↓
2. Create Episode Instance
   ↓
3. Get Prompt (initial state)
   ↓
4. Call Tools (actions)
   ├─ Receive reward
   ├─ Check finished flag
   └─ If not finished, repeat step 4
   ↓
5. Delete Episode (cleanup)
```

### Example Flow

```http theme={null}
# 1. Create session ID
POST /create_session
→ {"sid": "abc-123"}

# 2. Create episode instance with task
POST /create
Headers: X-Session-ID: abc-123
Body: {
  "env_name": "math",
  "task_spec": {"question": "What is 2+2?", "answer": "4"},
  "secrets": {}
}
→ {"sid": "abc-123"}

# 3. Get initial prompt
GET /math/prompt
Headers: X-Session-ID: abc-123
→ [{"text": "What is 2+2?", "detail": null, "type": "text"}]

# 4. Call tool
POST /math/call
Headers: X-Session-ID: abc-123
Accept: text/event-stream
Body: {"name": "submit", "input": {"answer": "4"}}
→ SSE stream (see below for format)

# 5. Delete episode
POST /delete
Headers: X-Session-ID: abc-123
→ {"sid": "abc-123"}
```

## Endpoint Categories

ORS endpoints fall into four categories:

### 1. Discovery Endpoints

Get information about the environment:

```http theme={null}
GET /list_environments        # List available environments
GET /{env_name}/tools        # List available tools
GET /{env_name}/splits       # List available splits
POST /{env_name}/tasks       # List tasks for a split
```

These are **stateless** - no session required.

### 2. Session Management

Create and manage episodes:

```http theme={null}
POST /create_session         # Generate session ID
POST /create                 # Create episode instance
POST /delete                 # Delete episode
POST /delete_session         # (Cleanup - optional)
POST /ping                   # Keep session alive
```

These require the **X-Session-ID header** (except create\_session).

### 3. Episode Interaction

Interact with the active episode:

```http theme={null}
GET /{env_name}/prompt       # Get initial prompt
POST /{env_name}/call        # Call a tool
```

These require **X-Session-ID** and an active episode.

### 4. Health

```http theme={null}
GET /health                  # Server health check
```

## Session Management

### X-Session-ID Header

Episodes are identified by a session ID passed in the `X-Session-ID` header:

```http theme={null}
POST /create
X-Session-ID: abc-123
```

**Flow**:

1. Call `POST /create_session` to get a session ID
2. Use that ID in all subsequent requests
3. Server maintains episode state for that ID
4. Call `POST /delete` to clean up

### Session Timeout

Sessions automatically expire after **15 minutes of inactivity**.

To prevent timeout:

```http theme={null}
POST /ping
X-Session-ID: abc-123
```

Call `/ping` periodically to keep the session alive. The reference SDK pings every 10 seconds; at minimum, ping well before the 15-minute timeout.

## Tool Execution with SSE

Tool calls return results via **Server-Sent Events**:

```http theme={null}
POST /{env_name}/call
Headers:
  X-Session-ID: abc-123
  Accept: text/event-stream
Body: {
  "name": "bash",
  "input": {"command": "ls -la"}
}
```

Response (SSE stream):

```
event: task_id
data: 877bb56c594e4a0f921ad55c439a3762

event: end
data: {"ok": true, "output": {"blocks": [{"text": "Output text", "detail": null, "type": "text"}], "metadata": null, "reward": 0.0, "finished": false}}
```

For large responses (>4KB), the result is split across `chunk` events before the final `end` event. See [Server-Sent Events](/specification/sse) for the full event type reference.

### Why SSE?

Server-Sent Events are used because:

* **Long-running tool calls**: Keeps connections alive while tools execute (bash commands, LLM calls, etc.)
* **Chunking large responses**: Results over 4KB are split into chunks for reliable delivery
* **Reconnection**: Clients can reconnect with a task ID and retrieve completed results
* **Standard protocol**: Built into browsers and HTTP libraries

## Error Handling

### HTTP Status Codes

Standard HTTP status codes:

* **200 OK**: Successful request
* **400 Bad Request**: Invalid input
* **404 Not Found**: Session/environment/tool not found
* **500 Internal Server Error**: Server error

### SSE Errors

Errors can also arrive as SSE events during tool execution streaming:

```
event: task_id
data: task-xyz-790

event: error
data: Session not found
```

These represent server-level failures (session not found, tool not recognized, internal error). They are distinct from tool logic errors, which return `{"ok": false, "error": "..."}` in an `end` event. See [Server-Sent Events](/specification/sse#error) for details.

### Tool Errors

Tool execution errors are returned in the ToolOutput:

```json theme={null}
{
  "ok": false,
  "error": "Tool 'submit' failed: Invalid answer format"
}
```

Successful tool calls:

```json theme={null}
{
  "ok": true,
  "output": {
    "blocks": [{"text": "Correct!", "detail": null, "type": "text"}],
    "metadata": null,
    "reward": 1.0,
    "finished": true
  }
}
```

## Stateful Sessions

Sessions maintain state across tool calls:

```python theme={null}
# Episode state persists between calls
session.call_tool("bash", {"command": "echo 'hello' > file.txt"})
session.call_tool("bash", {"command": "cat file.txt"})
# → "hello"
```

**What's maintained**:

* Environment-specific state (variables, files, etc.)
* Task context
* Episode progress

**What ends an episode**:

* Client calls `POST /delete` (explicit cleanup — calls environment's `teardown()`)
* Session times out after 15 minutes of inactivity (automatic reaper)

<Note>
  The `finished: true` signal indicates the episode is **logically complete** from an RL perspective (e.g., the agent submitted a correct answer). It does **not** trigger automatic server-side teardown. The client should call `POST /delete` to free resources after receiving `finished: true`.
</Note>

**What's NOT maintained**:

* State across different sessions

## Security Considerations

### Secrets

Tasks can receive secrets via the `secrets` field:

```http theme={null}
POST /create
Body: {
  "env_name": "web_env",
  "task_spec": {...},
  "secrets": {
    "api_key": "sk-..."
  }
}
```

Secrets are passed to the environment when a session is created. The environment can use those secrets for internal
logic of the environment. For example, a model provider API key an be used to initialise an LLM client within the environment for an LLM grader.

### Isolation

ORS sessions are isolated at the protocol level. Each session ID maps to its own environment instance with independent state. But deeper isolation depends on the server implementation:

* **Protocol-level**: Each session has its own environment instance and state
* **Implementation-level**: Filesystem, network, and process isolation require additional infrastructure (e.g., containers, sandboxes)

## Implementation Approaches

### Option 1: Use [ORS Python SDK](https://github.com/openrewardstandard/python-sdk)

The Python SDK implements the full ORS protocol:

```python theme={null}
from ors import Environment, Server, tool

class MyEnvironment(Environment):
    @classmethod
    def list_splits(cls):
        return ["train", "test"]

    # ... implement other methods

server = Server([MyEnvironment])
server.run(port=8080)
```

The SDK handles:

* HTTP endpoint routing
* Session management
* SSE response delivery
* Error handling

### Option 2: Implement from Scratch

Implement the protocol in any language:

1. Create HTTP server
2. Implement required endpoints
3. Manage session state
4. Return tool outputs via SSE

See [Implementation Guide](/guides/implementing-server) for details.

## Next Steps

<CardGroup cols={2}>
  <Card title="HTTP API Reference" icon="book" href="/specification/http-api">
    Complete endpoint documentation
  </Card>

  <Card title="Data Types" icon="shapes" href="/specification/data-types">
    Request and response schemas
  </Card>

  <Card title="Session Management" icon="clock" href="/specification/sessions">
    Deep dive on episodes and sessions
  </Card>
</CardGroup>

***

**Key Takeaway**: ORS is a straightforward HTTP protocol with RESTful endpoints for discovery and management, plus SSE for delivering tool execution results. It's designed to be simple to implement in any language.
