Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
e1ea87e
style(tests): normalize launcher test formatting
Steel-tech Jul 28, 2026
e9e9fae
ci(browser): add minimal validation workflow
Steel-tech Jul 27, 2026
fad75b4
[pi] Implemented and committed Browser CI.
Steel-tech Jul 27, 2026
d78c2b0
feat(recording): add run-scoped observation bundles
Steel-tech Jul 28, 2026
4c9f75e
[pi] Implemented, committed, and pushed Browser 0.6.0.
Steel-tech Jul 28, 2026
b79c25b
fix(recording): harden evidence state transitions
Steel-tech Jul 28, 2026
d913414
chore(browser): close Wave 0 drift and CI gaps
Steel-tech Jul 28, 2026
e857e5c
test(renderer): isolate optional runtime dependencies
Steel-tech Jul 28, 2026
c0672b1
[pi] Implemented, committed, and pushed the Browser rep...
Steel-tech Jul 28, 2026
b8a1d0e
chore(browser): revert local formatting-only changes
Steel-tech Jul 28, 2026
8ccc8b8
fix(recording): close confirmed stop publication window
Steel-tech Jul 28, 2026
b09a567
feat(network): pure diff and formatting helpers for failed requests
Steel-tech Aug 4, 2026
2912942
feat(network): optional network() reader on the browser wrapper
Steel-tech Aug 4, 2026
c3b7652
feat(network): poll-mode failure feed in tick() with silent baseline
Steel-tech Aug 4, 2026
a1b3d43
feat(network): live-mode failure poll timer with activity-held cadence
Steel-tech Aug 4, 2026
9759a85
docs: describe failed-request lines in the console region
Steel-tech Aug 4, 2026
e14aed3
refactor(network): drop write-only pending set from diff state
Steel-tech Aug 4, 2026
28cd530
Merge pull request #3 from StructuPath/feat/network-failures-console
Steel-tech Aug 4, 2026
f87fe69
Potential fix for pull request finding
Steel-tech Aug 4, 2026
42d4d1a
Potential fix for pull request finding
Steel-tech Aug 4, 2026
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
34 changes: 34 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
---
name: CI

"on":
pull_request:
push:

permissions:
contents: read

jobs:
validate:
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Check out repository
# v4.2.2
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: "3.11"
- name: Set up Node.js
# v4.0.3
uses: actions/setup-node@1e60f620b9541d16bece96c5465dc8ee9832be0b
with:
node-version: 20
run: npm test
- name: Validate shell syntax
run: bash -n scripts/*.sh
- name: Run ShellCheck
run: shellcheck scripts/*.sh
- name: Validate plugin manifest
run: node scripts/check-manifest.mjs
49 changes: 43 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ Conductor).
- **Shared agent sessions** — one isolated browser session per Herdr workspace.
- **Live push streaming** — frames, URL/title changes, console messages, and
page errors arrive over WebSocket, with transparent polling fallback.
- **Failed network requests** — 4xx/5xx and no-response xhr/fetch/document
requests appear in the console region as `✖ 404 GET <url>` lines, in both
streaming and polling modes.
- **Pane-aware layout** — the browser viewport fits the pane without stretching
or changing its responsive width; the console opens only when output exists.
- **Real interaction** — clicks use Chrome mouse events rather than DOM selector
Expand Down Expand Up @@ -197,8 +200,17 @@ viewport width—and therefore its responsive breakpoint—while fitting only th
height to the pane's image area. The frame fills that area without stretching.

On a quiet page, the image uses all rows between the header and controls. The
console region appears only after a console message or page error arrives; the
viewport then refits to the remaining image area.
console region appears only after a console message, page error, or failed
network request arrives; the viewport then refits to the remaining image area.

Failed network requests paint as `✖ 404 GET <url>` (HTTP 400–599) or
`✖ no response GET <url>` (connection-level failures, detected after ~15
seconds without a status). Only xhr, fetch, and document requests are watched —
images, stylesheets, and held-open streams (SSE, WebSocket) stay out. Failures
from before the pane attached are intentionally not replayed, repeated
identical failures are collapsed within a 60-second window, and on very long
sessions the feed turns itself off with a one-time note once the daemon's
request log outgrows the pane's read buffer.

## Session model

Expand Down Expand Up @@ -229,16 +241,38 @@ echo "my-agent-session" \

## Recording

Start and stop recording through the two recording actions. Files are written
to:
Start and stop recording through the existing recording actions. Each new
capture is a run-scoped observation bundle:

```text
<Herdr plugin state>/recordings/herdr-ws-<id>-YYYYMMDD-HHMMSS.webm
<Herdr plugin state>/runs/run-<run-id>/browser/
evidence.json
recording.webm
```

Set `HERDR_BROWSER_RUN_ID`, or put a run ID on the first line of
`<plugin config>/run-id`. IDs must be 1–128 ASCII letters, digits, dots,
underscores, or hyphens and must start with a letter or digit. When neither is
set, Browser generates an ID. One active recording is allowed per workspace;
Stop always uses the run and browser session pinned by Start, even if the
current environment changed.

On successful Stop, `evidence.json` records the WebM byte count and SHA-256.
The bundle is an **unreviewed, operator-reviewable observation**, not a test
result, acceptance decision, provenance claim, or cryptographic attestation.
Its digest detects later content changes but does not identify who recorded or
reviewed it. A missing, empty, non-regular, symlinked, or oversized WebM is not
marked complete. A confirmed failed Stop retains a retryable active pointer.
Before invoking Stop, Browser durably marks the attempt pending; if the process
is interrupted while its outcome is unknown, later Stop actions fail closed
without calling the non-idempotent engine again or marking evidence complete.
That pending pointer remains occupied for manual inspection and reconciliation.

Starting a recording creates a fresh browser context: the page reloads, while
cookies and localStorage are preserved. Start recording before the flow you
want to capture. Recordings persist until you delete them.
want to capture. Bundles persist until you delete them. Files created by 0.5
under `recordings/*.webm` remain untouched as legacy, unscoped recordings and
are not relabeled or migrated.

## Configuration

Expand All @@ -247,13 +281,15 @@ Plugin config files contain one value on their first line:
| File | Values | Default | Purpose |
| --- | --- | --- | --- |
| `session` | Session name | `herdr-ws-<workspace-id>` | Watch a different agent-browser session |
| `run-id` | Valid run ID | Generated | Correlate a recording bundle with an external run |
| `render` | `kitty`, `symbols`, `text` | Automatic probe | Force a rendering mode |

Equivalent environment controls:

| Variable | Default | Purpose |
| --- | --- | --- |
| `HERDR_BROWSER_SESSION` | Workspace session | Override the watched session |
| `HERDR_BROWSER_RUN_ID` | Config or generated ID | Select the recording run ID |
| `HERDR_BROWSER_RENDER` | Automatic probe | Override the rendering mode |
| `HERDR_BROWSER_INTERVAL_MS` | `1000` | Polling interval; clamped to safe bounds |
| `AGENT_BROWSER_IDLE_TIMEOUT_MS` | `1800000` | Idle timeout for plugin-created browser daemons |
Expand All @@ -267,6 +303,7 @@ Environment variables take precedence over config files.
- Workspace identifiers are sanitized before they are used in state paths.
- Polling frames are cached as PNG; streamed frames are cached as JPEG. Frame
files are mode `0600` and removed when the pane exits.
- Recording bundles use private directories (`0700`) and files (`0600`), and session names are metadata only—never path components.
- WebM recordings are intentionally retained under the plugin state directory.
- Browser sessions are a trusted local boundary: any local process that knows a
session name can drive it, including authenticated pages.
Expand Down
Loading