# OpenRath v2.0.0 Agent Server and Remote Client The Agent Server turns a registered durable workflow into tenant-scoped HTTP and SSE resources. `RemoteClient` and `AsyncRemoteClient` provide the matching Python client surface. ```text Workflow + immutable revision | v AgentServer | +-------+--------+ | | HTTP resource API SSE Run events | RemoteClient / AsyncRemoteClient ``` The `/v1` prefix is the version of the Agent Server HTTP contract. The product release documented on this page is Stable OpenRath `v2.0.0`. ## Install the server profile Install the exact Stable release with the Agent Server dependencies: ```bash python -m pip install \ "openrath[server] @ https://github.com/Rath-Team/OpenRath/releases/download/v2.0.0/openrath-2.0.0-py3-none-any.whl" ``` The embedded example below uses SQLite. For a PostgreSQL deployment, install `openrath[server,postgres]` and follow the [operations guide](operations.md). ## Create an embedded Agent Server Save this application as `server_app.py`: ```python from pathlib import Path from uuid import UUID from rath.definition import EffectClass, step from rath.flow import Workflow from rath.runtime import LocalRuntime, SQLiteRunStore from rath.security import ( Principal, PrincipalKind, SecurityContext, StructuredAuditSink, ) from rath.server import AgentServer, StaticTokenAuth from rath.session import Session class EchoWorkflow(Workflow): @step(entry=True, effects=EffectClass.READ_ONLY) def echo(self, state, context): return {**state, "completed": True} # The v1 callable façade remains available in v2.0.0. def forward(self, session: Session) -> Session: return session store = SQLiteRunStore(Path("agent-server.db")) runtime = LocalRuntime(store) security = SecurityContext( principal=Principal(id="local-client", kind=PrincipalKind.SERVICE), tenant_id="local", grants=frozenset( { "assistant.read", "session.create", "session.read", "run.create", "run.read", "run.cancel", "run.resume", "interrupt.read", "interrupt.decide", "feedback.create", "metrics.read", } ), ) server = AgentServer( store, runtime, auth=StaticTokenAuth({"replace-this-local-token": security}), audit_sink=StructuredAuditSink(), embedded_worker=True, ) server.register_assistant( "echo", EchoWorkflow(), revision_id=UUID("00000000-0000-4000-8000-000000000001"), ) app = server.app ``` `StaticTokenAuth` is the reference bearer-token provider for self-hosted deployments and tests. An integrated deployment can implement the `AuthProvider` protocol and produce its own `SecurityContext`. Start the application: ```bash openrath-server --app server_app:app --host 127.0.0.1 --port 8000 ``` The server starts one embedded durable worker because the application sets `embedded_worker=True`. ## Submit and inspect a Run In another terminal, save this as `client.py`: ```python from time import sleep from rath.client import RemoteClient client = RemoteClient( "http://127.0.0.1:8000", token="replace-this-local-token", ) try: session = client.create_session() run = client.create_run( assistant_id="echo", session_id=session["id"], state={"message": "hello from the Agent Server"}, idempotency_key="agent-server-quickstart-1", ) for _ in range(50): run = client.get_run(run["id"]) if run["status"] not in {"queued", "running"}: break sleep(0.1) else: raise TimeoutError("the Run did not finish") assert run["status"] == "succeeded" print(run["state"]) for event in client.events(run["id"]): print(event["sequence"], event["type"]) finally: client.close() ``` Run it: ```bash python client.py ``` `AsyncRemoteClient` exposes the same resource operations as native async methods. Its `events(...)` method asynchronously iterates the durable event replay endpoint. ## Follow Run events over SSE The SSE endpoint accepts an event cursor through `after` or `Last-Event-ID`. With `follow=true`, it waits for new events and exits after a terminal Run has no more events to emit: ```bash curl -N \ -H "Authorization: Bearer replace-this-local-token" \ "http://127.0.0.1:8000/v1/runs/RUN_ID/stream?after=0&follow=true" ``` Each event contains a durable sequence number, type, timestamp, Run ID, and JSON data. A client can reconnect with the last processed sequence without replaying earlier events. ## Service endpoints | Endpoint | Purpose | | --- | --- | | `GET /health/live` | Process liveness. | | `GET /health/ready` | Durable-store readiness. | | `GET /info` | Server capabilities and bounds. | | `GET /openapi.json` | Generated Agent Server contract. | | `GET /metrics` | Prometheus metrics; requires `metrics.read`. | | `/v1/assistants` | Deployment templates and tenant aliases. | | `/v1/sessions` | Durable Session resources. | | `/v1/runs` | Create, list, inspect, cancel, and resume Runs. | | `/v1/runs/{run_id}/events` | Ordered event replay. | | `/v1/runs/{run_id}/stream` | Cursor-resumable SSE events. | | `/v1/interrupts` | Pending approvals and decisions. | | `/v1/feedback` | Run feedback records. | | `/v1/store` | Governed Memory operations when configured. | The full request and response schemas are in the [OpenAPI document](https://github.com/Rath-Team/OpenRath/blob/v2.0.0/deploy/docs/openapi-v2.json). ## Server command-line tools | Command | Contract | | --- | --- | | `openrath-server --app module:app` | Runs the ASGI application. OpenRath uses one process worker and scales through service replicas. | | `openrath-worker --app module:server` | Runs a separate durable worker for an `AgentServer` object. | | `openrath-migrate` | Applies the PostgreSQL schema with a DDL-capable identity. | | `openrath-migrate --check` | Verifies the current PostgreSQL schema without applying changes. | For a separate worker deployment, construct the server with `embedded_worker=False`, export the `AgentServer` object as `server`, and run: ```bash openrath-server --app server_app:app openrath-worker --app server_app:server --worker-id worker-1 ``` Continue with [Operations](operations.md) for PostgreSQL migration, immutable images, backup and restore, rollout, and incident workflows.