---
title: "report.session-write-request@1 · OpenVibe.Services"
canonical: "https://openvibe.services/docs/contracts/report.session-write-request"
updated: null
---

# report.session-write-request@1 · OpenVibe.Services

HTML: [report.session-write-request@1 · OpenVibe.Services](https://openvibe.services/docs/contracts/report.session-write-request)

# ReportSessionWriteRequest `report.session-write-request@1`

Generated at 2026-11-13 06:25:48 UTC from [`openvibe-contracts v0.419.0`](https://github.com/OpenVibers/OpenVibe.Contracts/tree/v0.419.0) and [`openvibe-sdk v0.161.0`](https://github.com/OpenVibers/OpenVibe.SDK/tree/v0.161.0).

- Version: 1.0.0
- Owner: report
- Visibility: first-party
- Status: active
- Compatibility: backward
- Schema: [`https://openvibe.network/contracts/report/session-write-request.v1.json`](/docs/contracts/report.session-write-request.json)

report.session-write-request@1 (the Agent Streams plan, S3): the body of POST /internal/session-reports on OpenVibe.Report (capability report.session.write). The caller is a first-party service - Codes, Actor or Live - holding that capability for the audience openvibe.report; the body names the person the session was theirs. The route is idempotent per (SOURCE, TASK.REF): a repeat of the same session's task answers the report already stored, with created false. The report's id is Report's own (rps\_<ULID>); the body never carries one. Every text field passes the house redactor before anything is stored, so no secret and no raw transcript is ever stored.

## Fields

| Field | Type | Required | Description | Constraints |
| --- | --- | --- | --- | --- |
| `owner` | string | yes | The person the session was theirs. | - `pattern ^usr_[0-9A-HJKMNP-TV-Z]{26}$` |
| `source` | enum | yes |  | - `one of "codes", "actor", "desk", "node"` |
| `task` | `https://openvibe.network/contracts/report/session-write-request.v1.json#/$defs/task` | yes |  |  |
| `started_at` | string | yes |  | - `format date-time` |
| `ended_at` | string | yes |  | - `format date-time` |
| `worked_seconds` | integer | yes |  | - `minimum 0` |
| `outcome` | enum | yes |  | - `one of "done", "stopped", "failed"` |
| `stopped_because` | string |  |  | - `minLength 1`<br>- `maxLength 300` |
| `summary` | string | yes |  | - `minLength 1`<br>- `maxLength 600` |
| `timeline` | `https://openvibe.network/contracts/report/session-write-request.v1.json#/$defs/step` |  |  |  |
| `outputs` | `https://openvibe.network/contracts/report/session-write-request.v1.json#/$defs/output` |  |  |  |
| `proof` | `https://openvibe.network/contracts/report/session-write-request.v1.json#/$defs/proof` |  |  |  |
| `cost_usd` | number \| null |  |  | - `minimum 0` |
| `models` | array of string |  |  | - `items: minLength 1`<br>- `items: maxLength 120` |
| `highlights` | array of string |  |  | - `maxItems 5`<br>- `items: minLength 1`<br>- `items: maxLength 200` |
| `stream` | object \| null |  |  |  |
| `visibility` | enum |  | Who may see it. Absent means private. | - `one of "private", "unlisted", "public"` |
| `stream_only` | boolean |  | Live's stream-only report: the session is the stream itself and no tool will finish it. Absent or false means a normal session report. |  |

## Examples

From the contract's own test fixtures: valid ones validate, rejected ones must fail.

 Valid: request

~~~~
{
  "owner": "usr_01JAN2C3D4E5F6G7H8J9K0MNPS",
  "source": "codes",
  "task": {
    "title": "Ship the checkout page",
    "ref": "tsk_01JAN2C3D4E5F6G7H8J9K0MNPS",
    "url": "https://openvibe.codes/t/tsk_01JAN2C3D4E5F6G7H8J9K0MNPS"
  },
  "started_at": "2026-11-06T18:00:00.000Z",
  "ended_at": "2026-11-06T18:42:00.000Z",
  "worked_seconds": 2520,
  "outcome": "done",
  "summary": "Asked for a checkout page; the agent built it, ran the tests and opened a pull request.",
  "timeline": [
    {
      "at": "2026-11-06T18:20:00.000Z",
      "title": "Run the checkout tests",
      "status": "passed",
      "tests": {
        "passed": 12,
        "failed": 0
      }
    }
  ],
  "outputs": [
    {
      "kind": "pr",
      "url": "https://forgejo.example/openvibe/site/pulls/7",
      "title": "Checkout page",
      "state": "open"
    }
  ],
  "proof": {
    "tests": {
      "passed": 12,
      "failed": 0
    },
    "screenshots": [
      "med_01JAN2C3D4E5F6G7H8J9K0MNPS"
    ],
    "review": {
      "verdict": "Looks good",
      "notes": null
    }
  },
  "cost_usd": 0.31,
  "models": [
    "claude-sonnet-4"
  ],
  "highlights": [
    "Found the coupon bug on the first read"
  ],
  "visibility": "private"
}
~~~~

Rejected: no-owner

~~~~
{
  "source": "codes",
  "task": {
    "title": "Ship the checkout page",
    "ref": "tsk_1"
  },
  "started_at": "2026-11-06T18:00:00.000Z",
  "ended_at": "2026-11-06T18:42:00.000Z",
  "worked_seconds": 2520,
  "outcome": "done",
  "summary": "Asked for a checkout page."
}
~~~~

## Validate

~~~~
const contracts = require('openvibe-contracts');
contracts.validate('report.session-write-request@1', value);   // { valid, errors: [{ path, message }] }
~~~~
