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

# AgentOS Read Endpoints

> Inspect runs, replay sessions, and list approval requirements over HTTP

AgentOS can list and inspect past runs, replay a session's transcript, and list which tools require approval — all over HTTP, with `503` (not an empty list) when the underlying store is missing.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Client[🖥️ Client] --> OS[🚀 AgentOS]
    OS --> Runs[📜 /api/runs]
    OS --> Sessions[💬 /api/sessions]
    OS --> Approvals[🔐 /api/approvals]
    Runs --> Ledger[💾 SQLiteRunLedger]
    Sessions --> Store[💾 Session store]
    Approvals --> Registry[📋 Approval registry]

    classDef client fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef server fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef route fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef store fill:#10B981,stroke:#7C90A0,color:#fff

    class Client client
    class OS server
    class Runs,Sessions,Approvals route
    class Ledger,Store,Registry store
```

## Quick Start

**1. Attach a ledger and serve**

Attaching a `SQLiteRunLedger` unlocks `/api/runs` and `/api/runs/{run_id}`.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonai import AgentOS
from praisonaiagents import Agent
from praisonaiagents.runs import SQLiteRunLedger

app = AgentOS(agents=[Agent(instructions="Be helpful")])
app.run_ledger = SQLiteRunLedger()   # unlocks /api/runs and /api/runs/{id}
app.serve(port=8000)
```

**2. Read runs over HTTP**

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
curl http://localhost:8000/api/runs?limit=10
curl http://localhost:8000/api/runs/<run_id>
```

***

## Enabling Each Endpoint

Each endpoint reads a store you attach to the `AgentOS` instance.

> [tab] Runs
>
> Attach a run ledger to expose `/api/runs` and `/api/runs/{run_id}`.
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents.runs import SQLiteRunLedger
>
> app.run_ledger = SQLiteRunLedger()
> ```
>
> See [Run Ledger](https://praison.ai/docs/features/run-ledger.md).

> [tab] Sessions
>
> Attach a session store with `recent()`, `get_chat_history()`, and optionally `session_exists()` to expose `/api/sessions` and `/api/sessions/{session_id}`.
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents.session import DefaultSessionStore
>
> app.session_store = DefaultSessionStore()
> ```
>
> See [SQLite Transcript Store](https://praison.ai/docs/features/sqlite-transcript-store.md) and [Session Persistence](https://praison.ai/docs/features/session-persistence.md).

> [tab] Approvals
>
> No attribute needed. `/api/approvals` reads the process-global registry populated by `add_approval_requirement(...)` / `require_approval(...)`.
>
> ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> from praisonaiagents.approval import add_approval_requirement
>
> add_approval_requirement("delete_file", risk_level="high")
> ```
>
> See [Approval Protocol](https://praison.ai/docs/features/approval-protocol.md).

***

## Endpoint Reference

Five read-only routes, each returning `503` naming what to configure when its store is absent.

| Method | Path | Purpose | Missing-store behaviour |
| - | - | - | - |
| GET | `/api/runs?limit=50` | List runs from the attached ledger. `limit` bounded `1 ≤ limit ≤ 500`. | `503` — no run ledger configured; attach a `SQLiteRunLedger` as `run_ledger`. |
| GET | `/api/runs/{run_id}` | Fetch a single run. | `503` if no ledger; **`404`** if the ledger returns `None` for that id. |
| GET | `/api/sessions?limit=20` | List recent sessions. `limit` bounded `1 ≤ limit ≤ 200`. | `503` if `session_store` is unset or lacks `recent()`. |
| GET | `/api/sessions/{session_id}?limit=100` | Return the transcript for one session. `limit` bounded `1 ≤ limit ≤ 500`. | `503` if no store; **`404`** if `session_exists(session_id)` is `False`, or the store has no `session_exists()` and the transcript is empty. |
| GET | `/api/approvals` | List global + per-agent approval requirements. | `503` if `praisonaiagents.approval` is not installed or the registry exposes no requirement listing. |

***

## Response Shapes

Every response matches the endpoint's contract exactly.

> [accordion] GET /api/runs
>
> Each run is the record's own `as_dict()` (or `vars()`) — ledgers with extra fields are not truncated.
>
> ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> { "runs": [ { "run_id": "r1", "status": "done" } ], "count": 1 }
> ```

> [accordion] GET /api/runs/\{run\_id}
>
> The record's dict directly — no wrapper.
>
> ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> { "run_id": "r1", "status": "done", "agent": "researcher" }
> ```

> [accordion] GET /api/sessions
>
> ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> { "sessions": [ { "session_id": "s1", "messages": 4 } ], "count": 1 }
> ```

> [accordion] GET /api/sessions/\{session\_id}
>
> The chat history as the store returns it.
>
> ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> { "session_id": "s1", "messages": [ { "role": "user", "content": "hi" } ] }
> ```

> [accordion] GET /api/approvals
>
> ```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> { "requirements": [ { "tool": "delete_file", "agent": null, "risk_level": "high" } ] }
> ```

***

## Why the Errors Look Like This

> [!NOTE]
>
> A missing store returns **`503` naming what to configure**, not an empty list. An empty list is indistinguishable from *"no runs yet"* and lets an operator debugging a missing run conclude the run never happened. An unknown run or session is **`404`**, not an empty object, for the same reason. Out-of-range `limit` values return **`422`** — SQLite treats `LIMIT -1` as unlimited, so the bounds are pinned deliberately.

***

## Choosing an Endpoint

This decision diagram maps a question to the endpoint that answers it.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Q{What do you want?} --> A[List everything]
    A --> R1[/api/runs, /api/sessions, /api/approvals/]
    Q --> B[Replay ONE session]
    B --> R2[/api/sessions/id/]
    Q --> C[Inspect ONE run]
    C --> R3[/api/runs/id/]
    Q --> D[Is this run alive?]
    D --> R4[/api/runs/id + SQLiteRunLedger/]

    classDef q fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef opt fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef out fill:#10B981,stroke:#7C90A0,color:#fff

    class Q q
    class A,B,C,D opt
    class R1,R2,R3,R4 out
```

***

## How Operators Interact

An operator lists runs; the ledger either answers or the endpoint says what to attach.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Ops as Operator
    participant OS as AgentOS
    participant Store as Ledger / Session store

    Ops->>OS: GET /api/runs?limit=10
    alt ledger attached
        OS->>Store: list_all(limit=10)
        Store-->>OS: [RunRecord, ...]
        OS-->>Ops: 200 {"runs": [...], "count": N}
    else no ledger
        OS-->>Ops: 503 "no run ledger is configured…"
    end
```

***

## Best Practices

> [accordion] Attach a ledger in production
>
> The `503` names what to attach, but you want the endpoint to actually work. Attach a `SQLiteRunLedger` before deploying.

> [accordion] Treat 503 as a config bug, not a request bug
>
> A `503` means the store is missing, not that the request was malformed. Do not retry it — fix the configuration.

> [accordion] Read-only on purpose
>
> Mutating a run over HTTP is a much larger design question. Use the SDK for changes; these endpoints only read.

> [accordion] Keep limit conservative
>
> The upper bounds (`runs ≤ 500`, `sessions ≤ 200`) exist because clients can otherwise ask for a full-table scan. Request only what you need.

***

## Related

> [card] [AgentOS](https://praison.ai/docs/concepts/agentos.md)
>
> The AgentOS platform and its routes.

> [card] [Run Ledger](https://praison.ai/docs/features/run-ledger.md)
>
> Attach a SQLiteRunLedger to record runs.

> [card] [SQLite Transcript Store](https://praison.ai/docs/features/sqlite-transcript-store.md)
>
> Persist session transcripts for replay.

> [card] [Approval Protocol](https://praison.ai/docs/features/approval-protocol.md)
>
> Require approval for sensitive tools.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.