A watch wakes a session when a PR it opened changes. The agent opens a PR, declares a watch, and ends the turn; when checks finish, a review or comment lands, or the PR merges, OpenComputer appends a normalized event and wakes the session to react. This is the open-a-PR-then-respond-to-CI loop without polling GitHub.
Preview — APIs may change before general availability.
Declare a watch from inside the sandbox with the watch_pull_request runtime tool, or from your backend with the REST endpoints below.
How it works
Declaring a watch doesn’t change session state — the session goes idle after the turn like any other. On a PR transition, OpenComputer appends an event and wakes the session, the same path as a steer.
- Authoritative re-read. A webhook is a hint. Before waking, OpenComputer re-reads PR state from GitHub and wakes with that snapshot, so late, duplicate, or out-of-order webhooks converge.
- Coalesced. One wake per transition — a burst of check events for a commit is a single
checks_completed wake.
- Loop-suppressed. The session’s own comments and pushes don’t wake it; only third-party changes do.
- Delivered as
user events. The event is appended at level user (source: "github") and the session resumes with prior context.
A watch lets the agent react; it doesn’t grant a GitHub write path. There is no comment-write tool — the agent reads the event and responds by pushing a fix to the branch or opening a follow-up PR. It cannot post a reply comment to GitHub.
What you can watch
A session can only watch a PR it opened itself via github_publish_pull_request. The PR must have been opened through the OpenComputer GitHub App (oc_app sources) — that App’s webhook and read token are what drive the watch. Inline risky_short_lived_token sources aren’t watchable (the token is checkout-only and purged).
Owner-side prerequisite. The OpenComputer GitHub App needs Pull requests: Read, Checks: Read, and Issues: Read, plus event subscriptions to pull_request, pull_request_review, pull_request_review_comment, check_suite, check_run, and issue_comment. Existing installs must re-accept the new permissions. Until they do, a watch is created but declares as auth_required and won’t deliver events.
Wake conditions
wake_on is the wake condition — the PR state change that wakes the session. It’s what the watch waits for; the why is intent, replayed on wake.
wake_on | Wakes when |
|---|
checks | GitHub check runs/suites for the head commit finish (default). Legacy commit statuses aren’t watched. |
review | A review decision lands — approved or changes-requested (not plain comments). |
comment | A new comment on the PR (review comment or issue comment). |
merge | The PR reaches a terminal state — merged, or closed without merging. |
events is derived from wake_on; it is not part of the create request.
intent (why)
intent is a freeform note — why the agent is watching (e.g. “Fix CI if it fails”). It doesn’t affect when the session wakes; it’s replayed back to the agent on wake so it knows what to do.
The agent declares and clears watches from inside the sandbox. Full signatures: Runtime tools.
| Tool | What it does |
|---|
watch_pull_request(wake_on?, repo?, pr?, intent?) | Subscribe to a PR the session opened. Does not block — call it, then finish the turn. Defaults to the most recent PR the session opened; wake_on defaults to checks. intent is a freeform note replayed on wake. |
unwatch_pull_request(repo?, pr?) | Stop watching. Defaults to the only active watch. |
Management API
Manage watches from your backend with the SDK, the oc CLI, or REST — authenticated with your org API key (server-side). repo/pr are optional; omitted, they resolve to the PR this session opened.
Create a watch:
const session = await oc.sessions.get("ses_...");
const watch = await session.watches.create({
repo: "acme/web", // optional — defaults to the PR this session opened
pr: 42, // optional
wakeOn: "review", // checks (default) · review · comment · merge
intent: "Address review feedback on the auth refactor.",
});
// → { id: "wch_...", status: "active", ... }
List watches:
const watches = await session.watches.list();
Delete a watch:
await session.watches.delete("wch_...");
The watch object
| Field | Notes |
|---|
id | wch_… |
type | github_pr |
repo pr | the watched repo and PR number |
wake_on | the wake condition (table above) |
intent? | freeform note, replayed on wake |
status | lifecycle status (below) |
origin | how it was declared (runtime tool or management API) |
last_snapshot_at? | last authoritative PR re-read |
expires_at | when the 30-day TTL lapses; past this the watch stops firing (status stays active) |
created_at | timestamp |
Statuses
| Status | Meaning |
|---|
active | Watching; delivering events. |
closed | The PR merged or closed, so the watch ended with it. |
revoked | Removed via unwatch_pull_request or DELETE. |
auth_required | The App lacks the required permissions or event subscriptions — re-accept them. Re-declare the watch once fixed. |
A watch that hits its 30-day TTL simply stops firing (its expires_at passes) — re-declare to renew it.
Delivered events
One event per transition, appended at level user with source: "github". The body is a normalized summary (a comment event carries author, text, and URL), never the raw webhook.
type | Fires on |
|---|
github.pr.checks_completed | Check suites for the head commit finished (coalesced). |
github.pr.review_submitted | A review decision was submitted (approved / changes requested). |
github.pr.comment | A comment landed on the PR — issue-style or review (diff) comment. |
github.pr.merged | The PR merged. |
github.pr.closed | The PR closed without merging. |
These join the standard session event types — switch on type, don’t parse prose.
Limits
- Max 10 active watches per session.
- 30-day TTL, and never outlives the PR — the watch ends when the PR closes or merges.
Example
- Agent calls
github_publish_pull_request("web", "Refactor auth") → PR opened on branch oc/<session>/web-<id>.
- Agent calls
watch_pull_request(wake_on: "review", intent: "Address review feedback"), says, ends the turn. Session goes idle.
- Reviewer comments. OpenComputer re-reads the PR, appends
github.pr.comment (author, text, URL) at level user, and wakes the session.
- Agent edits the source and calls
github_publish_pull_request again to push onto the same branch. Its own push is loop-suppressed. The watch runs until the PR merges or the TTL expires.