Download all docs
tools

Recorder

A receive-only camera on a live Chromeless browser session: it ingests the cb-chromium WebRTC track verbatim, muxes it into durable WebM segments in a `files` store, and projects the session's audit timeline into a replayable `events.jsonl` — so what an agent or user saw can be watched back later.

Working with it

Selecting a Recorder reveals its settings in the properties panel; it has no dedicated full-screen workbench.

How it appears

The same element type rendered as a definition, a circle instance, and a live workspace card.

Rc
type

Recorder

Records native Chromeless WebRTC browser sessions to durable WebM segments + a finalized event timeline in a `files` store, replayable later.

toolsmodifierdefinition

When to use / not

When to use

  • Capturing what a Chromeless / cb-chromium browser actually rendered during an automated or agent-driven session, for replay or audit.
  • Bracketing a flow step with start/stop so a specific stretch of browser work lands as a durable recording you can list and read back.
  • Producing a timestamped event timeline (clicks, navigations, marks) alongside the video, via append-event / append-events into the recording's audit slice.
  • Attaching to a browser-facing element (chromeless, user-browser, view, spa) as a fail-open modifier whose failure never blocks the work it observes.

When not to use

  • Driving or scripting the browser itself — recorder only observes; use chromeless (or user-browser) to navigate and act.
  • Storing arbitrary blobs or general project artifacts — write those straight to a files element; recorder owns only the recordings/ prefix.
  • Capturing a still frame or a one-off screenshot — recorder produces continuous WebM segments, not a single image.

Topology

Attaches to another element as a modifier, shaping that element's behaviour rather than running on its own.

Properties

segment_target_duration_msinteger
Target wall-clock duration of a single WebM segment, in milliseconds. The muxer closes the current segment and opens a new one whenever elapsed time crosses this threshold AND it lands on a keyframe boundary, so actual durations skew slightly larger on low-keyframe content. Lower values shrink the "last segment lost on crash" window at the cost of more files in the recordings store.
size_cap_bytesinteger
Soft cap on the total bytes occupied by `recordings/` in this recorder's files store. When exceeded, the reaper evicts the oldest finalized recordings (whole sessions) until the prefix is back under the cap. In-flight `recording` sessions are NEVER evicted — only `finalized` or `failed` ones. Default 5 GiB at runtime (per `recorder-reaper-defaults.md` — sized below the ENOSPC blast radius demonstrated by reform-receiver PVC fill incidents).
ttl_daysinteger
Maximum age in days for a finalized recording. The reaper removes any recording whose `ended_at` is older than this. Combined with `size_cap_bytes` via OR — the older of the two wins, so a recording evicts as soon as EITHER its age exceeds ttl_days OR the cap pushes it off the tail. Placeholder default (14 days); coordinate with store-builder before tuning.
files_element_refstring
Default files element (slug or UUID) this recorder writes recordings into. When empty, every `start` op falls back to the circle's primary files element. Per-op `files_element_ref` overrides this.

Capabilities

Defined for this element
  • Webrtc
  • Compute

Operations

  • activityGET
  • append-eventPOST
  • append-eventsPOST
  • attachPOST
  • attachmentsGET
  • batch_statsGET
  • composePOST
  • contextGET
  • createPOST
  • deleteDELETE
  • detachPOST
  • disablePOST
  • enablePOST
  • exportPOST
  • export_bundleGET
  • getGET
  • import_bundlePOST
  • intentionGET
  • invokePOST
  • listPOST
  • list_attachmentsGET
  • logsGET
  • mcp_tool_defGET
  • promotePOST
  • readmeGET
  • readme_updatePOST
  • remove-modifierPOST
  • resetPOST
  • restorePOST
  • run_getGET
  • runsGET
  • schemaGET
  • sourceGET
  • source_branchesGET
  • source_promotePOST
  • source_repairPOST
  • source_statusGET
  • source_validatePOST
  • startPOST
  • statsGET
  • statusPOST
  • stopPOST
  • treeGET
  • updatePATCH
  • update_metaPATCH
  • versionGET

Ports

Inputs

  • startrequest
  • manifestrequest

Composition

Recorder (recorder)

Category: tools | Form: | Symbol: Rc

Records native Chromeless WebRTC browser sessions to durable WebM segments + a finalized event timeline in a files store, replayable later.

Tool element shaped like chromeless — simultaneously an attachable modifier AND a thing with invokable ops. Records what an agent or user saw inside a chromeless session: a receive-only webrtc-rs peer joins the existing Pattern C broker as the client role, ingests the cb-chromium browser track verbatim (no decode, no re-encode), and muxes WebM segments into the circle’s files store under recordings/{session_id}/. Finalize writes a manifest + events.jsonl projection of the recording’s Iggy audit slice. v1 ships explicit start/stop ops only — no auto-start-on-attach. The append-event / append-events ops auto-emit PlatformEvents to the Iggy spine via the dispatcher chokepoint (per universal-events.md). MP4 export is async and out of band. fail_action is “allow” so a recorder failure never blocks the attached element.

Guide

Records native Chromeless WebRTC browser sessions to durable WebM segments + a finalized event timeline in a files store, replayable later

What It Does

Recorder is a tool element shaped like chromeless — it is simultaneously an attachable modifier and a thing with invokable ops. It records what an agent or user saw inside a Chromeless session: a receive-only webrtc-rs peer joins the existing Pattern C broker as the client role, ingests the cb-chromium browser track verbatim (no decode, no re-encode), and muxes WebM segments into the circle’s files store under recordings/{session_id}/.

You bracket a recording with the start and stop ops from a flow step. start allocates a session_id derived from (circle_id, browser_element_id), resolves the target files element, writes an initial RecordingManifest (status='recording'), and begins muxing the VP8/Opus track into segments under recordings/{session_id}/segments/. stop closes the receiver peer, finalizes the current segment, sets status='finalized', and writes events.jsonl — a timestamp-ordered projection of the recording’s Iggy audit slice. v1 ships explicit start/stop only; there is no auto-start-on-attach.

The append-event / append-events ops push entries onto the recording’s Iggy audit slice; the dispatcher chokepoint auto-emits a PlatformEvent on every op completion, which is exactly what feeds the audit_stream that stop projects into events.jsonl. MP4 export is async and out of band via the export op. As a modifier, fail_action is allow, so a recorder failure never blocks the attached element.

Element Definition

PropertyValue
Typerecorder
Categorytools
Formmodifier (modifier_type: recorder)
SymbolRc / #EF4444
Iconfiber_manual_record

As a modifier it applies_to: [actors, frontend], cascades to the nearest instance, evaluates in the request phase (evaluation_order: 50), and on failure takes fail_action: allow. It attaches to: chromeless, user-browser, view, spa, ssr, function, triformer, hitl. It uses the files and chromeless elements.

Properties

FieldTypeDefaultDescription
segment_target_duration_msinteger4000Target wall-clock duration of a single WebM segment, in ms (500–60000). The muxer rotates on a keyframe boundary past this threshold.
size_cap_bytesinteger0Soft cap on total bytes under recordings/ in this recorder’s files store. 0 = use the runtime ReaperPolicy default. In-flight recording sessions are never evicted.
ttl_daysinteger14Maximum age in days for a finalized recording (1–365). The reaper removes recordings whose ended_at is older than this. Combined with size_cap_bytes via OR.
files_element_refstring""Default files element (slug or UUID) recordings are written into. Empty falls back to the circle’s primary files element. Per-op files_element_ref overrides it. (maxLength 128)
active_session_idsarray[]Session IDs currently in recording status. Read-only; the executor maintains it.
last_started_atstring (date-time)""ISO 8601 timestamp of the most recent start op.
last_finalized_atstring (date-time)""ISO 8601 timestamp of the most recent stop (finalize) op.

Ports

DirectionPortRequiredDescription
InputstartStart a recording of a chromeless WebRTC session (StartInput).
OutputmanifestCurrent or finalized recording manifest (RecordingManifest).

Capabilities

CapabilityDescription
executableElement can be invoked to execute operations.
webrtc-receiveReceive-only webrtc-rs peer joins the Pattern C broker as the client role.
webm-muxMux received VP8/Opus RTP samples into WebM segments without decode/re-encode.
files-backed-artifactPersists recordings into a files element store under recordings/{session_id}/.
event-timelineFinalize projects the recording’s Iggy audit slice into a durable events.jsonl.
size-cap-reaperEnforces a configurable size cap + TTL on the recordings prefix.
mp4-exportAsync out-of-band MP4 export from finalized WebM segments.

Error Codes

CodeClassRetryableDescription
RECORDER_NO_LIVE_BROWSERnot_foundNoNo live chromeless session was found for the given browser_element_id.
RECORDER_BROKER_BUSYconflictNoThe Pattern C broker is strictly 1:1; another client peer is already attached to this session.
RECORDER_FILES_RESOLVE_FAILEDnot_foundNoCould not resolve a target files element (neither provided ref nor circle default).
RECORDER_STORE_FULLresource_exhaustedNoThe files store hit its size cap; the reaper could not free room for new segments.
RECORDER_FINALIZE_FAILEDinternalYesManifest finalize + events.jsonl projection write failed.

Operations

start

POST start — auth: write. Starts a recording of a chromeless WebRTC session. Allocates a session_id from (circle_id, browser_element_id), resolves the target files element, writes the initial manifest (status='recording', empty segments), joins the Pattern C broker as client, and begins muxing into recordings/{session_id}/segments/. Idempotent on session_id — re-calling start for an already-recording session returns the existing session_id without disrupting capture.

  • Input: browser_element_id (required), files_element_ref (optional).
  • Output: session_id, started_at.

stop

POST stop — auth: write. Stops a recording and finalizes the manifest + events.jsonl. Sends Bye {from:"client"}, closes the receiver peer, finalizes the current segment, sets ended_at, status='finalized', and audit_stream.offset_end, then writes events.jsonl. Safe to call on an already-finalized session — returns the persisted manifest unchanged.

  • Input: session_id (required).
  • Output: the finalized RecordingManifest.

status

POST status — auth: read. Reads the current or finalized RecordingManifest for a session exactly as persisted at recordings/{session_id}/manifest.json. While status='recording', the segments array grows as segments close.

  • Input: session_id (required).
  • Output: the RecordingManifest.

list

POST list — auth: read. Lists recordings in this recorder’s files store, newest first, returning the full RecordingManifest for each entry.

  • Input: limit (optional, default 50, max 500), since (optional, RFC 3339 — only recordings with started_at strictly greater).
  • Output: recordings (array of RecordingManifest).

export

POST export — auth: write. Kicks off an async post-finalize export (currently MP4 only). Returns immediately with export_status='pending' and a stable path under recordings/{session_id}/exports/. Only callable on status='finalized' sessions — errors on still-recording or failed sessions.

  • Input: session_id (required), format (required, enum ["mp4"]).
  • Output: export_status (pending | in_progress | ready | failed), path.

append-event

POST append-event — auth: write. Appends a single event entry to the recording’s audit timeline (Iggy slice, subject recorder.append-event.completed). The dispatcher chokepoint auto-emits the matching PlatformEvent on op completion, feeding the audit_stream that finalize projects into events.jsonl. (UI section: hidden.)

  • Input: session_id, kind (e.g. 'click', 'navigation', 'mark', 'annotation'), payload (free-form object), ts (RFC 3339, preserved verbatim) — all required.
  • Output: ok (true when published to the Iggy spine; the Iggy publish is the durability boundary).

append-events

POST append-events — auth: write. Batch variant of append-event. All items are published atomically into the recording’s Iggy audit slice, in order. Cap on batch size is enforced by the platform’s PlatformEvent batcher. (UI section: hidden.)

  • Input: session_id (required), items (required array, minItems 1; each item kind, payload, ts).
  • Output: ok, accepted (number of items the platform accepted).

Quick Start

Create a recorder

POST /api/{circle}/{project}/
Content-Type: application/json

{
  "element_type": "recorder",
  "slug": "session-recorder",
  "name": "Session Recorder",
  "spec": {
    "segment_target_duration_ms": 4000,
    "ttl_days": 14
  }
}

Start, then stop a recording

POST /api/{circle}/session-recorder/ops/start
Content-Type: application/json

{
  "browser_element_id": "<chromeless-element-uuid>"
}

The response carries the session_id and started_at. Bracket the work you want captured, then finalize:

POST /api/{circle}/session-recorder/ops/stop
Content-Type: application/json

{
  "session_id": "<session-id-from-start>"
}

stop returns the finalized RecordingManifest, including the segments[] list and the events_jsonl_path. Read it back any time with status, or browse all recordings with list.

Common Mistakes

Passing a session_id to start. start takes browser_element_id, not session_id — it allocates the session id from (circle_id, browser_element_id) and returns it. Every other op (stop, status, export, append-event, append-events) takes that returned session_id.

Recording a browser with no live session. start requires a live chromeless WebRTC session for the given browser_element_id; otherwise it returns RECORDER_NO_LIVE_BROWSER. The Pattern C broker is strictly 1:1 — a second client peer on the same session returns RECORDER_BROKER_BUSY.

Exporting before finalize. export is only callable on a status='finalized' session and supports format: "mp4" only. Calling it on a still-recording or failed session returns an error.

Expecting events.jsonl mid-recording. events.jsonl is written only at finalize (stop). While status='recording', observe progress by tailing the status op or watching the recorder’s PlatformEvents on the Iggy spine — the manifest’s segments[] grows as segments close.

Relationships

  • Attaches to: chromeless, user-browser, view, spa, ssr, function, triformer, hitl
  • Uses: files, chromeless

Capabilities

  • executable: Element can be invoked to execute operations
  • webrtc-receive: Receive-only webrtc-rs peer joins the Pattern C broker as the client role
  • webm-mux: Mux received VP8/Opus RTP samples into WebM segments without decode/re-encode
  • files-backed-artifact: Persists recordings into a files element store under recordings/{session_id}/
  • event-timeline: Finalize projects the recording’s Iggy audit slice into a durable events.jsonl
  • size-cap-reaper: Enforces a configurable size cap + TTL on the recordings prefix
  • mp4-export: Async out-of-band MP4 export from finalized WebM segments

Properties

PropertyTypeDefaultDescription
segment_target_duration_msinteger4000Target wall-clock duration of a single WebM segment, in milliseconds. The muxer closes the current segment and opens a new one whenever elapsed time crosses this threshold AND it lands on a keyframe boundary, so actual durations skew slightly larger on low-keyframe content. Lower values shrink the “last segment lost on crash” window at the cost of more files in the recordings store.
size_cap_bytesinteger0Soft cap on the total bytes occupied by recordings/ in this recorder’s files store. When exceeded, the reaper evicts the oldest finalized recordings (whole sessions) until the prefix is back under the cap. In-flight recording sessions are NEVER evicted — only finalized or failed ones. Default 5 GiB at runtime (per recorder-reaper-defaults.md — sized below the ENOSPC blast radius demonstrated by reform-receiver PVC fill incidents).
ttl_daysinteger14Maximum age in days for a finalized recording. The reaper removes any recording whose ended_at is older than this. Combined with size_cap_bytes via OR — the older of the two wins, so a recording evicts as soon as EITHER its age exceeds ttl_days OR the cap pushes it off the tail. Placeholder default (14 days); coordinate with store-builder before tuning.
active_session_idsarray[]Session IDs currently in recording status. Cleared as each session finalizes. Read-only from the user surface; the executor maintains it.
last_started_atstring""ISO 8601 timestamp of the most recent start op for this recorder.
last_finalized_atstring""ISO 8601 timestamp of the most recent stop op (finalize) for this recorder.
files_element_refstring""Default files element (slug or UUID) this recorder writes recordings into. When empty, every start op falls back to the circle’s primary files element. Per-op files_element_ref overrides this.

Operations

activity

Get /ops/activity | Auth: Read

Get activity events for this element

Scope depends on element capabilities: individual elements query by element_id, project-form elements with activity-scope-members include member activities, circle-level elements with activity-scope-all query the entire circle. Gracefully returns empty list if activities table is missing (old circles).

attach

Post /ops/attach | Auth: Read

Attach this tool to a target agent element

This is the critical operation that grants an agent access to tools. POST the tool’s attach endpoint with target_id=<agent_uuid>. The agent’s enabled_tools list is recomputed on every invocation, so attaching/detaching takes effect on the next agent run. The target must be an element listed in the tool’s contract.yaml attaches list (typically agents).

attachments

Get /ops/attachments | Auth: Read

List all modifiers and resources attached to this element

Returns both modifiers (policy enforcement) and resources (data injection) with is_modifier flag to distinguish. Items in the generated MODIFIER_TYPES list are modifiers; everything else is a resource. Includes cascade_policy and version pin info.

batch_stats

Get /ops/batch_stats | Auth: Read

Get per-element statistics for all children of this element

Returns per-child stats plus an aggregate. Most meaningful on compound or manifest form elements (repositories, circles, projects); atoms have no children so the result is an empty children array with a zeroed aggregate. Uses efficient GROUP BY SQL. Weighted averages for eval scores.

compose

Post /ops/compose | Auth: Execute

Batch add and remove modifiers on this element in a single call

Declarative composition: add modifiers by ref path (slug or path@version) and remove by attachment ID, all in one atomic call on the target element. Each ‘add’ entry resolves the source element, validates topology, attaches with optional priority and cascade policy. Each ‘remove’ entry deletes the attachment row. Returns a summary of what was added and removed. Example: compose({ add: [{ref: “my-prompt”}, {ref: “rate-limit/api@v2”, priority: 50}], remove: [{attachment_id: “uuid”}] })

context

Get /ops/context | Auth: Read

Get connected elements (graph traversal)

Graph traversal showing all connected elements with their relationship type (contains, contained_by, references, referenced_by, attaches, etc.). Use ?depth=N to control traversal depth (default 1) and ?types=actor,data to filter by element types.

create

Post /ops/create | Auth: Write

Create child element

POST to the parent path — element_type goes in the request body, NOT the URL. Both element_type and slug are required and must be non-empty. Name is derived from slug if omitted. Writes to both Git and PostgreSQL. All elements are stored flat under the circle — no intermediate library wrapper rows.

delete

Delete /ops/delete | Auth: Admin

Delete element (soft delete)

Soft delete — sets state to ‘deleted’ but retains the record. Cannot delete elements that have children (has_no_bond precondition) or active runs. Requires admin auth and confirmation.

detach

Post /ops/detach | Auth: Read

Detach this tool from a target agent element

Removes tool access from the agent. Takes effect on next agent invocation. Requires the same target_id used in attach.

disable

Post /ops/disable | Auth: Admin

Disable element (hides and prevents use)

Idempotent — safe to call on already-disabled elements. Optionally pass a reason string. Disabled elements cannot be invoked or executed. Inverse of enable.

enable

Post /ops/enable | Auth: Admin

Enable element (makes usable and visible)

Idempotent — safe to call on already-enabled elements. Transitions element to ready/enabled state. Cannot enable deleted elements. Inverse of disable.

export

Post /ops/export | Auth: Write

Kick off an async post-finalize export (currently MP4 only)

Schedules an out-of-band export from the finalized WebM segments into the requested container/codec. v1 supports format: "mp4" only. Returns immediately with export_status='pending' and a stable path under recordings/{session_id}/exports/ once the worker has reserved a slot. Subsequent calls to status reflect export progress in the manifest’s exports[] array. Only callable on status='finalized' sessions; returns an error on still-recording or failed sessions.

export_bundle

Get /ops/export/bundle | Auth: Read

Export element as downloadable git bundle

On non-root-namespace elements, returns a binary git bundle. On root-namespace (circle) elements, dispatch hands off to the circle’s own export_bundle op, which returns a multi-element JSON envelope with one base64 bundle per child element — this is intentional, not an error.

get

Get /ops/get | Auth: Read

Get element details

Element is already resolved by the routing layer — this returns the cached element, not a fresh DB query. Use the path /api/{circle}/{slug} to address elements.

import_bundle

Post /ops/import/bundle | Auth: Write

Import git bundle into element

Accepts a base64-encoded git bundle in the JSON bundle_base64 field. Use overwrite=true to replace existing elements with same slug (default skips duplicates). Imported elements get new UUIDs. Returns counts of imported/skipped elements and any errors.

intention

Get /ops/intention | Auth: Read

Get element intention with full inheritance chain

Returns three levels: direct (this element’s intention), inherited (from category and root), and resolved (final merged intention). Useful for understanding an element’s purpose in context of its hierarchy.

invoke

Post /ops/invoke | Auth: Execute

Invoke the tool with input

Tools are primarily invoked indirectly by agents (the agent loop calls tools automatically). Direct invoke is for standalone testing. Input must match the tool’s port schema. Use ?async=true to get a run_id for polling. Browser tools return screenshots as base64 PNG.

list

Post /ops/list | Auth: Read

List recordings in this recorder element’s files store

Walks the recordings/ prefix in the resolved files store and returns the full RecordingManifest for each entry, newest first. limit caps the number of returned manifests (default 50, max 500). since filters to recordings whose started_at is strictly greater than the provided RFC 3339 timestamp.

list_attachments

Get /ops/targets | Auth: Read

List all agents this tool is attached to

Returns all agent elements where this tool is currently attached. Shows target_id, target_type, priority, and cascade_policy.

logs

Get /ops/logs | Auth: Read

Get execution logs

mcp_tool_def

Get /ops/mcp/tool | Auth: Read

Get this tool’s MCP tool definition (name, description, inputSchema)

promote

Post /ops/promote | Auth: Admin

Promote element configuration to a target environment

Only for manifest-form elements (projects). Environments advance: dev → demo → live. dev→demo requires member+ role, demo→live requires admin. Freezes member versions at promotion time (creates snapshot). Persists environment config to spec.environments.

readme

Get /ops/readme | Auth: Read

Get element README.md content

Reads README.md from the element’s git repository. Returns empty content (not an error) if no README exists. Always returns markdown format.

readme_update

Post /ops/readme_update | Auth: Write

Update element README.md content

Creates or overwrites README.md in the element’s git repo. Commits to the draft branch. Content must be provided as a markdown string.

remove-modifier

Post /ops/remove-modifier | Auth: Execute

Remove an attached modifier from this element by attachment ID

Removes a modifier/resource attachment by its row ID. The ID comes from the attachments or context API. This is the reverse of attach — called on the target element, not the source.

reset

Post /ops/reset | Auth: Execute

Reset tool state to idle

Use when a tool is stuck in error state. Resets to idle so it can be invoked again. For browser tools, this also clears the CDP session — the next navigation starts fresh.

restore

Post /ops/restore | Auth: Admin

Restore element to a specific version

Automatically snapshots the current state before restoring (creates a ‘Before restore to vN’ version entry). Writes restored spec to git as .triform/spec.yaml. Git failures warn but don’t fail the operation — DB state is authoritative. Cannot restore deleted elements.

run_get

Get /ops/runs/{run_id} | Auth: Read

Get details of a specific run

runs

Get /ops/runs | Auth: Read

List execution runs

schema

Get /ops/schema | Auth: Read

Get input/output port schemas (MCP tools/list compatible)

Returns the MCP-compatible tool schema. Useful for validating what inputs a tool expects before invoking. For platform tools, the schema reflects currently enabled capabilities.

source

Get /ops/source | Auth: Read

Get any file’s content from the element’s git repository

Reads an arbitrary file from the element’s CAS-backed git tree by its relative path. Same store as readme, just generalized. Path safety: rejects .. traversal, leading /, and null bytes. Use this to view main.py for action elements, asset files for SPAs, etc. Returns empty content (not an error) if the file doesn’t exist.

source_branches

Get /ops/source/branches | Auth: Read

List Source branches for this element

Returns the standard draft/demo/live Source branches, their current commits, and promotion relationships. Use GET /api/{element_path}/ops/source/branches.

source_promote

Post /ops/source/promote | Auth: Write

Promote Source branch forward

Promotes draft to demo or demo to live through the generated element op path. Direct Git pushes to demo/live are blocked by Source policy.

source_repair

Post /ops/source/repair | Auth: Write

Inspect or repair the element Source index

Runs Source repair through the element operation path. Defaults to dry_run=true; set dry_run=false only after reviewing a dry-run report.

source_status

Get /ops/source/status | Auth: Read

Get Source control status for this element

Returns the branch-aware clone URL, checkout commands, current draft commit, child source-link count, portable export summary, Source health, warnings, and auth hints for the addressed element. Use the element-first path: GET /api/{element_path}/ops/source/status.

source_validate

Post /ops/source/validate | Auth: Read

Validate Source branch contents

Validates a Source branch before accepting local Git workflow changes or promotion. Defaults to branch=draft and rejects runtime data, generated output, secret material, and unreadable CAS refs.

start

Post /ops/start | Auth: Write

Start a recording of a chromeless WebRTC session

Allocates a session_id derived from (circle_id, browser_element_id), resolves the target files element (files_element_ref or circle default), writes the initial RecordingManifest (status=‘recording’, empty segments), joins the Pattern C broker as the client role, and begins muxing the VP8/Opus track into WebM segments under recordings/{session_id}/segments/. Idempotent on session_id: re-calling start for an already-recording session returns the existing session_id without disrupting capture.

stats

Get /ops/stats | Auth: Read

Get aggregate statistics for this element

Health status is computed: error if errors_per_day > 5 or success_rate < 0.8, warning if errors_per_day > 0 or success_rate < 0.95. Firing alerts escalate health to error/warning. Default period is ‘day’. Returns runs_per_day, success_rate, avg_duration_ms, and more.

status

Post /ops/status | Auth: Read

Read the current or finalized RecordingManifest for a session

Returns the full manifest exactly as persisted in the files store under recordings/{session_id}/manifest.json. While status='recording' the segments array grows as segments close; consumers tail this op or watch the recorder’s PlatformEvents on the Iggy spine.

stop

Post /ops/stop | Auth: Write

Stop a recording and finalize the manifest + events.jsonl

Sends Bye {from:"client"} to the broker, closes the receiver peer, finalizes the current segment, sets ended_at + status='finalized' + audit_stream.offset_end, then writes events.jsonl as the projection of the recording’s Iggy audit slice. Returns the finalized RecordingManifest. Safe to call on an already-finalized session — returns the persisted manifest unchanged.

tree

Get /ops/tree | Auth: Read

Get the element’s position in the graph — ancestors, children, references, and subtree statistics

Uses per-circle ElementGraph cache for O(1) lookups. Returns ancestors (containment chain), children (direct), members (references), referenced_by (reverse refs), attachments, and subtree stats. Default depth is 3, max is 10. Pass ?include_metadata=true for name/state on each node.

update

Patch /ops/update | Auth: Write

Update element

Partial update — send only the fields you want to change. spec, name, and intention are all independently optional. spec MUST be a JSON object when present; deep-merged into the existing spec by default. Empty {"spec":{}} preserves existing spec content but still records a new version (no-op for content, not for version state). To clear/replace the entire spec wholesale send {"spec":{...},"deep":false}. List-typed spec fields use replace semantics (the patch list replaces the existing list, no array merging). Coordinates Git + DB writes. Slug cannot be changed after creation.

update_meta

Patch /ops/update_meta | Auth: Write

Update element metadata (lightweight merge — does NOT bump version or snapshot spec)

Shallow JSONB merge into element.meta. Top-level keys in the provided value replace existing meta values; other keys are preserved. Used for UI metadata like canvas positions, panel state, viewer preferences. Wire-shape op_name is update_meta (distinct from update) so SSE subscribers + the cache auto-invalidator can distinguish lightweight metadata changes from spec edits without inspecting the payload. The MutatingElementStore wrapper stamps this op_name on the lifecycle event emitted by update_element_meta storage calls.

version

Get /ops/version | Auth: Read

Get current version or full history

Returns current version by default. Pass ?history=true for full version history (up to ?limit=N, default 50). Versions are backed by the element_versions table. Every spec update creates a new version entry.

Error Codes

CodeClassRetryableDescription
RECORDER_NO_LIVE_BROWSERnot_foundnoNo live chromeless session was found for the given browser_element_id
RECORDER_BROKER_BUSYconflictnoThe Pattern C broker is strictly 1:1; another client peer is already attached to this session
RECORDER_FILES_RESOLVE_FAILEDnot_foundnoCould not resolve a target files element (neither provided ref nor circle default)
RECORDER_STORE_FULLresource_exhaustednoThe files store hit its configured size cap; the reaper could not free room for new segments
RECORDER_FINALIZE_FAILEDinternalyesManifest finalize + events.jsonl projection write failed

Observability

Defined for this element

Metrics

  • invocation_count
  • duration_ms
  • error_rate
  • recorder_session_started_count
  • recorder_session_finalized_count
  • recorder_session_failed_count
  • recorder_session_duration_ms
  • recorder_segment_count
  • recorder_segment_bytes
  • recorder_segment_duration_ms
  • recorder_segment_write_latency_ms
  • recorder_append_event_count
  • recorder_finalize_latency_ms
  • recorder_reaper_evicted_count
  • recorder_store_bytes

Events

  • recorder.completed
  • recorder.failed
  • recorder.start.completed
  • recorder.stop.completed
  • recorder.session.failed
  • recorder.segment.closed
  • recorder.append-event.completed
  • recorder.append-events.completed
  • recorder.reaper.evicted

Pricing / cost

Inherited from tools

Operation costs

  • tool_use: free