Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions skills/live-review/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
name: subtext:live-review
description: Open a Subtext live viewer session for real-time human-agent collaboration when making UI or frontend changes. Connects a hosted browser via the Subtext MCP server, shares a viewer URL so the human can watch the agent work, and polls for comments and signals throughout. Use when the user asks to build, fix, update, or modify any user-facing surface — components, pages, layouts, styles, copy, or routing. Also use when the user says "let me watch", "open a viewer", "start a live session", or requests live feedback on changes. Do NOT use for pure backend, API, or infrastructure changes with no visual impact.
metadata:
requires:
skills: ["subtext:shared", "subtext:live", "subtext:tunnel", "subtext:agent-playback-link", "subtext:comments"]
---

# Live Review

Real-time human-agent collaboration for UI development. The agent works in a hosted browser while the human watches via a Subtext viewer, leaving comments and annotations as feedback. The agent polls for signals between actions and adjusts its plan based on human input.

## When to Use

- User asks to build, fix, update, or modify a UI component, page, layout, style, or copy
- User says "let me watch", "open a viewer", "start a live session"
- User wants to give real-time feedback on visual changes
- Any task that will change what users see

## When NOT to Use

- Pure backend, API, or infrastructure changes
- Database migrations, feature flag config, gRPC endpoints
- Changes with no visual impact

## Setup Phase

Before starting implementation:

### 1. Determine the target URL

- If the user mentioned a specific page, infer the local dev URL
- If unclear, ask: "Which page should I open in the viewer?"
- Default to the app root (e.g. `http://localhost:3000`) if working on a global component

### 2. Connect the hosted browser

- Follow the `subtext:tunnel` flow to connect to the local dev server
- Follow the `subtext:live` connection pattern to open the page
- Authenticate if redirected to a login page

### 3. Share the viewer

- Follow the `subtext:agent-playback-link` pattern to construct and share the viewer URL
- Tell the user: "You can watch, leave comments, and annotate while I work. I'll check for your feedback between each action."

### 4. Start the signal heartbeat

- Follow the polling guidance in `subtext:live` (Pending Signals section)
- Check for signals between every subsequent action during implementation

### 5. Capture baseline state

- Screenshot the current page before making changes (upload with `upload=true`)
- Save the artifact URL — include it in the PR as "before" state alongside the viewer URL for downstream reviewers

## During Implementation

The agent proceeds with its normal implementation workflow (brainstorming, TDD, code edits, builds, etc.). This skill does NOT own the implementation — it provides the feedback loop around it.

**Between every action:**
- Call `live-poll` to check for pending signals
- If a `new_comment` signal arrives: read it, reply via `comment-reply`, adjust plan if the feedback redirects the work
- If a `control_change: human_driving` signal arrives: stop input actions, keep polling with read-only tools, wait for `control_change: agent_driving` before resuming

**After code changes that affect the UI:**
- Rebuild the frontend
- Refresh or re-navigate the live browser to pick up changes
- Screenshot the result for visual verification

## Teardown Phase

After implementation is complete:

### 1. Capture the final state

- Screenshot the result (upload with `upload=true`)
- Save as "after" artifact for the PR

### 2. Check for unresolved comments

- Call `comment-list` to review any comments from the human
- If unresolved comments remain, ask the user if they should be addressed before finishing

### 3. Disconnect

- Call `live-disconnect` to free the hosted browser
- Use the `subtext:agent-playback-link` pattern to construct a shareable playback link for the PR

### 4. Summarize for the PR

Include in the PR description:
- Before/after screenshots
- Agent playback link (so reviewers can replay the session)
- Any comment threads that informed the changes
53 changes: 37 additions & 16 deletions skills/live/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ API catalog for live browser tools (all prefixed `live-`) on the unified subtext

| Tool | Description |
|------|-------------|
| `live-connect` | Open a browser connection to a URL. Returns screenshot, component tree, `fs_session_url`, `viewer_url`, and `capture_status`. |
| `live-connect` | Open a browser connection to a URL. Returns screenshot, component tree, `fs_session_url`, and `viewer_url`. |
| `live-disconnect` | Close a browser connection. Returns `fs_session_url` and `viewer_url`. |
| `live-emulate` | Set device emulation (viewport, user agent, etc.) |

Expand Down Expand Up @@ -58,6 +58,12 @@ API catalog for live browser tools (all prefixed `live-`) on the unified subtext
| `live-net-list` | List network requests |
| `live-net-get` | Get details of a specific network request |

### Signals

| Tool | Description |
|------|-------------|
| `live-poll` | Check for pending signals (new comments, control changes) without taking a screenshot. Lightweight heartbeat. |
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wonder if we should have a tool that just does this and stores them somewhere the agent can see? getting the agent to poll for these on it's own might be unpredictable. not really sure what's best here tbh since even a sideband poll requires something back to claude or requires claude to do something to look.


### Tunnel

| Tool | Description |
Expand All @@ -72,7 +78,7 @@ Parameter schemas are visible in the tool definition at call time.

Both `fs_session_url` and `viewer_url` are returned by `live-connect`, `live-disconnect`, `live-view-navigate`, `live-view-new`, and `live-view-snapshot`.

- **fs_session_url** — the raw Fullstory session URL.
- **fs_session_url** — the raw FullStory session URL.
- **viewer_url** — a shareable link that opens the live viewer in a browser. **Always print this to the user** so they can watch the agent's browser in real time.

After every `live-connect`, output the viewer URL on its own line:
Expand All @@ -81,31 +87,46 @@ After every `live-connect`, output the viewer URL on its own line:
Viewer: {viewer_url}
```

## `live-connect` Capture Status

After every `live-connect`, check `capture_status` and respond as follows:

- `active`: proceed normally.
- `blocked`: tell the user to check capture quota and verify the target domain is allow listed in Subtext data capture settings.
- `snippet_not_found` or `api_unavailable`: tell the user something went wrong during setup and they should run onboarding again.
- any other status: something went wrong, try again

## Tips

- Always `live-view-snapshot` before interacting — you need element UIDs to click/fill.
- `live-view-snapshot` is cheaper than `live-view-screenshot`. Prefer snapshots; use screenshots for visual evidence.
- Component names from sightmap appear in snapshots — use `[src: ...]` annotations to find source files.
- Close connections when done to free server resources.

## Pending Signals

The server piggybacks **pending signals** on every tool response. When a human leaves a comment or changes control state, a `[pending_signals]` block appears at the end of the next tool response:

```
[pending_signals]
- new_comment: from chip@fullstory.com: "Try the other flow"
- control_change: human_driving — input tools are blocked
```

**Between actions, call `live-poll`** to check for signals without the overhead of a screenshot. This is your heartbeat — call it between every few actions in a live session to stay aware of human feedback.

**When you see a `new_comment` signal:**
1. Read the comment text — it may contain instructions, bug reports, or redirections
2. Use `comment-list` if you need full context (the signal only shows a preview)
3. Use `comment-reply` to acknowledge or respond
4. Adjust your plan based on the feedback

**When you see a `control_change: human_driving` signal:**
1. Input tools (click, fill, keypress) will return errors — don't retry them
2. Read-only tools (screenshot, snapshot, log-list, poll) still work
3. Keep polling — you'll see a `control_change: agent_driving` signal when control is returned
4. Resume your work after control is returned

## Tunnel Setup

When the hosted browser needs to reach `localhost` or local dev URLs, use the tunnel-first flow:
When the hosted browser needs to reach `localhost` or local dev URLs, set up a tunnel first:

1. Call `live-tunnel` — allocates a browser connection and returns `relayUrl` + `connectionId`
2. Call `tunnel-connect` on the **subtext-tunnel** MCP server with `relayUrl` and `target`
3. Call `live-view-new` with the `connection_id` and localhost URL
1. Call `live-tunnel` to get the relay URL
2. Call `tunnel-connect` on the **subtext-tunnel** MCP server with `relayUrl`, `connectionId`, and `target`
3. Then call `live-connect` with the localhost URL — traffic routes through the tunnel

Do **not** use `live-connect` for localhost URLs — it mints its own connection ID and can't bind to the tunnel. See `subtext:tunnel` for full details.
See `subtext:tunnel` for the full tunnel setup flow.

## See Also

Expand Down