> For the complete documentation index, see [llms.txt](https://docs.ethernity.cloud/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ethernity.cloud/developer-guide/the-guide/interactive-sessions.md).

# Interactive Sessions

A task normally runs once: payload in, result out. An **interactive session** keeps the enclaves alive for the entire order duration, so your dApp can exchange messages with the running enclave -- send an input, receive a verified reply, repeat -- while every message is anchored on-chain.

### How it works

You submit a task as a session (the request carries a session marker). The enclaves start normally, but instead of finishing after one execution they stay up for the `duration` you rented:

* **Inputs** are metadata rows on your DO request. Only your wallet can write them -- the smart contract enforces it -- so the chain itself authenticates every input. The content travels as ciphertext over IPFS, encrypted for the enclave, with its digest bound into the row.
* **Outputs** come back as metadata rows on the operator's DP request. Each row is signed by the enclave task wallet (`order.dproc`); the runner verifies the signature and the content digest before your code ever sees the message. An operator can transport messages but can never forge, alter, reorder, or silently drop them.
* **Settlement** is unchanged: one final result closes the order, carrying a commitment to the whole transcript. Validators recompute it from the on-chain rows alone and release payment only when everything matches -- a session where the operator interfered is refunded automatically (task code 39).

A session ends when you close it, or when the rented duration runs out. **Running out of time is a success, not an error**: the enclave finalizes with task code 0 and a summary (`reason: RUNNING_PERIOD_COMPLETE`) that accounts for every message.

### The payload handler

Define a handler in your payload. It runs once per input, and state created at startup persists across calls.

Python payloads:

```python
state = {"count": 0}

def handler(data):
    state["count"] += 1
    return "reply " + str(state["count"]) + ": " + str(data)
    ecld.on_input = handler
```

JavaScript payloads:

```javascript
ecld.onInput = async (data) => {
  return `reply: ${data}`;
}
```

A payload without a handler is not session-aware: every input is answered with an explicit `SESSION_HANDLER_NOT_DEFINED` error (code 5), announced on-chain before you even send the first message.

### Using sessions from the runner

Python (`ethernity-cloud-runner-py >= 0.4.19`):

```python
session = runner.run_session(resources, "my-enclave", "1", PAYLOAD)

seq = session.send_input("hello enclave")
msgs = session.wait_outputs(count=1, timeout=420)
print(msgs[0]["data"])

print(session.get_status())     # liveness from chain state alone
final = session.close()         # -> session summary
```

JavaScript (`ethernity-cloud-runner >= 0.4.9`):

```javascript
const session = await runner.runSession(resources, 'my-enclave', code);
const seq = await session.sendInput('hello enclave');
const [msg] = await session.waitOutputs(1);
console.log(msg.data);
const final = await session.close();
```

Also available: `on_output(callback)` for push-style consumption, and `list_sessions()` / `attach_session(orderId)` -- reattaching is fully stateless, so a restarted app resumes its running enclave with nothing persisted locally.

### Limits and timing

| Behavior       | Detail                                                                                               |
| -------------- | ---------------------------------------------------------------------------------------------------- |
| Session length | the order `duration` (hours). Billing is unchanged -- you rent the enclave for that time.            |
| Message cap    | 256 inputs and 256 outputs per session. Beyond the input cap the session terminates as a dApp fault. |
| Send cutoff    | `send_input` refuses during the last \~10 minutes so the enclave can wrap up cleanly.                |
| Late inputs    | an input racing the shutdown gets a signed `late` receipt instead of silence.                        |
| Round trip     | roughly one block time plus a polling tick per direction (\~10-20 s on the testnets).                |

### Session statuses

The final summary reports how the session ended -- all of these are task code 0:

| Status                | Meaning                                                                       |
| --------------------- | ----------------------------------------------------------------------------- |
| `closed`              | you sent `close()` -- ended on request.                                       |
| `complete-at-timeout` | duration exhausted with inputs processed -- the expected long-session ending. |
| `expired-idle`        | duration exhausted, no input was ever sent.                                   |
| `expired-unprocessed` | inputs arrived but none completed (e.g. the handler hung).                    |

### Error codes on output rows

An `error` output row carries its reason code on-chain, visible to any observer:

| Code | Meaning                                                                               |
| ---- | ------------------------------------------------------------------------------------- |
| 5    | the payload defines no `ecld.onInput` handler.                                        |
| 1    | the handler raised an exception (the encrypted payload carries the trace).            |
| 50   | malformed input row.                                                                  |
| 51   | out-of-order or duplicate input seq.                                                  |
| 52   | the input does not decrypt for this enclave.                                          |
| 53   | the securelock build predates sessions -- rebuild with the current SDK and republish. |

Task code **39** (`SESSION_RELAY_FAULT`) on the final result means the operator withheld input delivery or failed to broadcast signed output rows -- the transcript on-chain is incomplete and **the order is refunded**.

Sessions can use the Enclave State Registry too: a handler may read and commit ESR state on every message, with the usual ESR guarantees and caps applying across the whole session.
