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

# rb.observe

> Record the user's input and screenshots in a session a script can read back.

`rb.observe` records what the user does so a script can learn from it, as
[`rebind observe`](https://docs.rebind.gg/reference/cli#observe) does: every key and button press and
release with its hold time, mouse movement, scroll, the active window, the
display under the cursor, and screenshots. A script reaches for it to capture a
demonstration of a task, mark what happened, and read the recording back.

**Needs:** the `observe` [permission](https://docs.rebind.gg/reference/sdk/modeline.md#permissions),
which a script holds only when it lists it; a coroutine for `start`, `stop`,
`list`, `events`, `frame`, `rename` and `delete`, so call them inside `rb.run`
or `rb.async` (see [Where code runs](https://docs.rebind.gg/reference/sdk/globals.md#where-code-runs));
`min_sdk=3.15.0`.

This script starts a recording of up to 60 seconds on F7, which F8 ends early,
and marks the round won on F9:

```luau theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
-- rebind: min_sdk=3.15.0 name=example version=1.0.0 permissions=observe
rb.bind("F7", rb.async(function()
  local session = rb.observe.start({ seconds = 60, goal = "one round", stop_key = "F8" })
  rb.log.info("recording to", session.dir)
end))
rb.bind("F9", function()
  rb.observe.mark("success", "round won", { score = 12 })
end)
```

| Signature | Returns |
| - | - |
| `rb.observe.start(options: ObserveStartOptions?) -> ObserveStatus` | the new session's status |
| `rb.observe.stop() -> ObserveStatus` | the session's final counts and `reason` |
| `rb.observe.mark(kind: string, label: string?, data: any?) -> boolean` | `true` once the note is queued |
| `rb.observe.status() -> ObserveStatus?` | the running session, whoever started it, or `nil` |
| `rb.observe.list() -> { ObserveSummary }` | every recording, newest first |
| `rb.observe.events(id: string, from_seq: number?, to_seq: number?, max_bytes: number?) -> ObserveEvents` | log lines as tables, and `next`, the `seq` to ask for next |
| `rb.observe.frame(id: string, file: string, max_edge: number?) -> ObserveImage` | `mime`, `width`, `height` and `data`, the PNG as base64 |
| `rb.observe.rename(id: string, name: string) -> ObserveSummary` | the recording's summary with its new `name`; `""` clears it |
| `rb.observe.delete(id: string) -> string` | the id of the removed recording |

Outside a coroutine, a call that waits raises
`rb.observe.start waits for an answer: call it inside rb.run` (with the call's
name). `mark` and `status` answer at once and work anywhere.

`start` takes `seconds` (1 to 14,400, default 120), `stop_key` (a keyboard key
such as `"F8"` that ends the session early), `goal` (what the recording is for,
up to 500 characters), `frame_ms` (milliseconds between idle screenshots, 0 to
30,000, default 1000; 0 turns them off) and `frame_edge` (the long edge of
screenshots, 256 to 2048 pixels, default 1024). The status it returns holds the
session folder in `dir`.

One session runs at a time, whoever started it, so `start` raises
`rb.observe.start: An observation is already running` while one does. The
session's `owner` is the script's name (`rb.info.name`) and its `owner_kind` is
`"script"`; a session the app or the CLI started has `owner_kind` `"client"`.
It ends at `seconds`, at the stop key, on `stop`, or with the reason
`script_stopped` when the script stops, reloads or errors. The folder, the
reasons and the lines `events` returns are described under
[observe](https://docs.rebind.gg/reference/cli.md#observe).

A script marks and stops only the session it started, and renames or deletes
only recordings whose `owner_kind` is `"script"` and whose `owner` is its name,
such as one an earlier run made. Every script that declares the same
name can change the recordings made under it. A script reads every recording,
including the app's and the CLI's.

* `mark` returns `false` when this script has no session running or the note
  could not be queued.
* `stop` raises `rb.observe.stop: this script has no observation running`.
* `rename` and `delete` raise
  `rb.observe.delete: <id> was recorded by <owner_kind> <owner>, and a script changes only its own recordings`,
  and refuse a session that is still running.

`mark` writes a `mark` line among the inputs around it. `kind` is `"mark"`,
`"success"`, `"failure"`, `"ai"` or `"own"`; `label` is cut to 200 characters;
`data` is any value JSON can hold, at most 8 KB as JSON and 32 tables deep.

`events` returns the lines from `from_seq` (default 0) through `to_seq`,
stopping before `max_bytes` of them (default 262,144, 1 to 4,194,304) but
returning at least one. `frame` reads an image a line names, such as
`images/000001250-frame.png`, `images/000001250-window.png` or
`images/000001250-crop-41.png` (the
[session folder format](https://docs.rebind.gg/reference/cli.md#session-folder-format-1)), scaled down
so its long edge is at most `max_edge`. An image over 2 MB as
base64 raises and asks for a smaller `max_edge`. An id that is not a recording's,
or a file name that is not an observation image, raises.

Everything is recorded by name, passwords included, and screenshots show
whatever is on screen.


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