From a98d2773d3692d56026cf0bc15d9875deefa6971 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Tue, 5 May 2026 14:07:17 -0400 Subject: [PATCH 1/5] Define agent harness browser receipt surface --- docs/agent-harness-browser-receipts.md | 198 +++++++++++++++++++++++++ 1 file changed, 198 insertions(+) create mode 100644 docs/agent-harness-browser-receipts.md diff --git a/docs/agent-harness-browser-receipts.md b/docs/agent-harness-browser-receipts.md new file mode 100644 index 0000000..3adf0dc --- /dev/null +++ b/docs/agent-harness-browser-receipts.md @@ -0,0 +1,198 @@ +# Agent Harness Browser Receipt Surface + +Status: v0.1 planning baseline +Owner plane: BearBrowser governed browser runtime +Consumers: SourceOS spec, AgentPlane, Policy Fabric, Memory Mesh, SCOPE-D, Delivery Excellence + +## Purpose + +BearBrowser is the SourceOS browser surface for humans and agents. The Aden/Hive lessons make browser control a first-class production-agent requirement, but our posture is governance-first: visible, receipt-producing, policy-gated browser work rather than stealth or unbounded browser automation. + +This document defines how BearBrowser should emit browser receipts for the cross-estate agent harness loop. + +## Boundary + +BearBrowser owns: + +- governed browser sessions +- browser action evidence +- credential-use events +- download/upload manifests +- screenshot or DOM/action pointers +- automation-surface compatibility checks +- local provenance events +- browser policy-action proposals and verifiers + +BearBrowser does not own: + +- AgentPlane graph execution +- Policy Fabric gate authority +- Memory Mesh artifact storage +- Delivery Excellence scoreboards +- SCOPE-D security exercise execution +- SocioSphere topology authority + +## Receipt classes + +### BrowserSessionReceipt + +Records a governed browser session. + +Required semantics: + +- session id +- actor/agent ref +- workspace ref +- runtime profile +- policy admission ref +- network profile +- credential posture +- start/end timestamps +- headless/visible mode +- automation mode +- AgentPlane run/session refs + +### BrowserActionReceipt + +Records each meaningful browser action. + +Action classes: + +- navigate +- click +- type +- extract +- screenshot +- download +- upload +- form-submit +- login +- credential-use +- account-setting-change +- message-send +- purchase-or-order +- ticket-or-record-create + +Required semantics: + +- action id +- browser session ref +- URL/domain +- action class +- side-effect class +- policy decision ref +- screenshot pointer or DOM/action pointer +- credential-use flag +- upload/download artifact refs +- result status +- replay/simulation eligibility + +### BrowserDownloadReceipt + +Records files acquired through the browser. + +Required semantics: + +- download id +- source URL/domain +- file name +- sha256 +- media type +- size +- quarantine state +- scan refs +- Memory Mesh artifact pointer ref +- retention class +- policy decision ref + +### BrowserCredentialUseReceipt + +Records credential access or login action. + +Required semantics: + +- credential event id +- browser session ref +- credential scope +- provider/account alias +- policy decision ref +- human-control event ref when required +- no raw credential material +- result status + +## Policy requirements + +Require Policy Fabric decisions for: + +- login or credential use +- form submit +- upload +- download +- account-setting changes +- message sends +- purchase/order/ticket creation +- hidden/headless automation mode when the workflow is customer-facing or externally mutating +- any action outside the declared network profile + +Fail closed when a controlled action lacks a policy decision ref. + +## AgentPlane integration + +AgentPlane should cite BearBrowser receipts in: + +- RunArtifact +- ReplayArtifact +- SessionEnvelope +- EvidencePack +- FailureDiagnosis +- PromotionGate + +Browser receipts must be treated as evidence, not informal logs. + +## Memory Mesh integration + +Screenshots, DOM captures, extracted pages, downloads, and large browser outputs should be represented as Memory Mesh `ArtifactPointer` refs when they are large, sensitive, replay-critical, or customer-proof relevant. + +## Delivery Excellence integration + +Delivery Excellence should consume derived metrics/readouts: + +- browser action success/failure +- policy-blocked browser action count +- credential-use event count +- form-submit approval count +- download quarantine count +- replay-eligible browser action count +- customer-safe browser work proof + +Delivery Excellence should not consume raw browser payloads unless policy explicitly permits it. + +## SCOPE-D integration + +SCOPE-D should validate BearBrowser workflows for: + +- browser CSRF/local-origin abuse +- credential exfiltration +- malicious download bypass +- prompt injection through page content +- tool poisoning through browser-extracted instructions +- unauthorized form submit +- stealth/evasion misuse +- cross-domain network policy violations + +## Non-negotiables + +- BearBrowser does not default to stealth/evasion. +- Credential use is an evidence event. +- External side effects require policy refs. +- Downloads are artifact-managed and quarantine-aware. +- Customer-safe proof must be redacted and policy-approved. +- Headless mode must not erase evidence requirements. + +## Near-term implementation path + +1. Align existing BearBrowser provenance and policy-action schemas with this receipt surface. +2. Add examples for session, action, download, and credential-use receipts. +3. Add a verifier that ensures policy refs exist for controlled action classes. +4. Add a Delivery Excellence projection example for browser action metrics. +5. Add SCOPE-D browser-risk checks for credential, download, form-submit, and network-profile misuse. From 7b1b8b4ae8ecd24ced63687bb5fbfd859e320e13 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 16:13:08 -0400 Subject: [PATCH 2/5] Add agent harness browser receipts schema --- ...agent-harness-browser-receipts.schema.json | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 schemas/agent-harness-browser-receipts.schema.json diff --git a/schemas/agent-harness-browser-receipts.schema.json b/schemas/agent-harness-browser-receipts.schema.json new file mode 100644 index 0000000..971b843 --- /dev/null +++ b/schemas/agent-harness-browser-receipts.schema.json @@ -0,0 +1,73 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sourceos.dev/schemas/bearbrowser/agent-harness-browser-receipts.schema.json", + "title": "AgentHarnessBrowserReceipts", + "type": "object", + "additionalProperties": false, + "required": ["schemaVersion", "kind", "browserSessionReceipt", "browserActionReceipt", "browserDownloadReceipt", "browserCredentialUseReceipt"], + "properties": { + "schemaVersion": { "const": "v0.1" }, + "kind": { "const": "AgentHarnessBrowserReceipts" }, + "browserSessionReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["sessionId", "actorRef", "workspaceRef", "runtimeProfile", "policyAdmissionRef", "networkProfile", "credentialPosture", "mode", "agentplaneRunRef"], + "properties": { + "sessionId": { "type": "string" }, + "actorRef": { "type": "string" }, + "workspaceRef": { "type": "string" }, + "runtimeProfile": { "type": "string" }, + "policyAdmissionRef": { "type": "string" }, + "networkProfile": { "type": "string" }, + "credentialPosture": { "type": "string", "enum": ["none", "available-but-unused", "used-with-policy", "blocked"] }, + "mode": { "type": "string", "enum": ["visible", "headless"] }, + "agentplaneRunRef": { "type": "string" } + } + }, + "browserActionReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["actionId", "browserSessionRef", "url", "actionType", "sideEffectClass", "policyDecisionRef", "credentialUse", "resultStatus"], + "properties": { + "actionId": { "type": "string" }, + "browserSessionRef": { "type": "string" }, + "url": { "type": "string" }, + "actionType": { "type": "string", "enum": ["navigate", "click", "type", "extract", "screenshot", "download", "upload", "form-submit", "login", "credential-use", "account-setting-change", "message-send", "purchase-or-order", "ticket-or-record-create"] }, + "sideEffectClass": { "type": "string", "enum": ["none", "read-only", "external-write", "credential", "download", "upload"] }, + "policyDecisionRef": { "type": "string" }, + "credentialUse": { "type": "boolean" }, + "artifactPointerRefs": { "type": "array", "items": { "type": "string" } }, + "resultStatus": { "type": "string", "enum": ["succeeded", "failed", "blocked", "needs-human-review"] } + } + }, + "browserDownloadReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["downloadId", "sourceUrl", "sha256", "mediaType", "sizeBytes", "quarantineState", "memoryMeshPointerRef", "policyDecisionRef"], + "properties": { + "downloadId": { "type": "string" }, + "sourceUrl": { "type": "string" }, + "sha256": { "type": "string" }, + "mediaType": { "type": "string" }, + "sizeBytes": { "type": "integer" }, + "quarantineState": { "type": "string", "enum": ["not-required", "quarantined", "released", "blocked"] }, + "memoryMeshPointerRef": { "type": "string" }, + "policyDecisionRef": { "type": "string" } + } + }, + "browserCredentialUseReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["credentialEventId", "browserSessionRef", "credentialScope", "policyDecisionRef", "rawCredentialStored", "resultStatus"], + "properties": { + "credentialEventId": { "type": "string" }, + "browserSessionRef": { "type": "string" }, + "credentialScope": { "type": "string" }, + "policyDecisionRef": { "type": "string" }, + "humanControlEventRef": { "type": "string" }, + "rawCredentialStored": { "type": "boolean" }, + "resultStatus": { "type": "string", "enum": ["succeeded", "failed", "blocked", "needs-human-review"] } + } + } + } +} From f9dcc225c3c57fe5168eabf6abb2e078a92fdd88 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 16:58:01 -0400 Subject: [PATCH 3/5] Add agent harness browser receipts example --- ...gent-harness-browser-receipts.example.json | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 examples/agent-harness-browser-receipts.example.json diff --git a/examples/agent-harness-browser-receipts.example.json b/examples/agent-harness-browser-receipts.example.json new file mode 100644 index 0000000..513d487 --- /dev/null +++ b/examples/agent-harness-browser-receipts.example.json @@ -0,0 +1,45 @@ +{ + "schemaVersion": "v0.1", + "kind": "AgentHarnessBrowserReceipts", + "browserSessionReceipt": { + "sessionId": "bearbrowser-session-agent-harness-v0.1", + "actorRef": "github://mdheller", + "workspaceRef": "github://SocioProphet/sociosphere", + "runtimeProfile": "bearbrowser-governed-visible", + "policyAdmissionRef": "github://SocioProphet/policy-fabric/pull/60", + "networkProfile": "customer-safe-demo", + "credentialPosture": "available-but-unused", + "mode": "visible", + "agentplaneRunRef": "github://SocioProphet/agentplane/pull/107" + }, + "browserActionReceipt": { + "actionId": "browser-action-open-delivery-excellence-pr", + "browserSessionRef": "bearbrowser-session-agent-harness-v0.1", + "url": "https://github.com/SocioProphet/delivery-excellence/pull/9", + "actionType": "navigate", + "sideEffectClass": "read-only", + "policyDecisionRef": "github://SocioProphet/policy-fabric/pull/60", + "credentialUse": false, + "artifactPointerRefs": [], + "resultStatus": "succeeded" + }, + "browserDownloadReceipt": { + "downloadId": "browser-download-none-baseline", + "sourceUrl": "https://github.com/SocioProphet/delivery-excellence/pull/9", + "sha256": "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", + "mediaType": "application/json", + "sizeBytes": 0, + "quarantineState": "not-required", + "memoryMeshPointerRef": "github://SocioProphet/memory-mesh/pull/23", + "policyDecisionRef": "github://SocioProphet/policy-fabric/pull/60" + }, + "browserCredentialUseReceipt": { + "credentialEventId": "browser-credential-unused-baseline", + "browserSessionRef": "bearbrowser-session-agent-harness-v0.1", + "credentialScope": "none", + "policyDecisionRef": "github://SocioProphet/policy-fabric/pull/60", + "humanControlEventRef": "", + "rawCredentialStored": false, + "resultStatus": "succeeded" + } +} From b6c899843c727dd215f3fe4683bf7f7cd71a6e95 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 20:15:51 -0400 Subject: [PATCH 4/5] Verify agent harness browser receipts --- ...arbrowser-verify-agent-harness-receipts.py | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 scripts/bearbrowser-verify-agent-harness-receipts.py diff --git a/scripts/bearbrowser-verify-agent-harness-receipts.py b/scripts/bearbrowser-verify-agent-harness-receipts.py new file mode 100644 index 0000000..54b12bc --- /dev/null +++ b/scripts/bearbrowser-verify-agent-harness-receipts.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python3 +"""Verify BearBrowser Agent Harness receipt fixture.""" + +from __future__ import annotations + +import json +import sys +from pathlib import Path +from typing import Any + +ROOT = Path(__file__).resolve().parents[1] +SCHEMA = ROOT / "schemas" / "agent-harness-browser-receipts.schema.json" +EXAMPLE = ROOT / "examples" / "agent-harness-browser-receipts.example.json" + + +class ValidationError(Exception): + pass + + +def load_json(path: Path) -> Any: + with path.open("r", encoding="utf-8") as handle: + return json.load(handle) + + +def require(condition: bool, message: str) -> None: + if not condition: + raise ValidationError(message) + + +def validate(data: dict[str, Any]) -> None: + require(data.get("schemaVersion") == "v0.1", "schemaVersion must be v0.1") + require(data.get("kind") == "AgentHarnessBrowserReceipts", "kind mismatch") + + session = data.get("browserSessionReceipt") + require(isinstance(session, dict), "browserSessionReceipt must be object") + for field in ["sessionId", "actorRef", "workspaceRef", "runtimeProfile", "policyAdmissionRef", "networkProfile", "credentialPosture", "mode", "agentplaneRunRef"]: + require(field in session, f"browserSessionReceipt missing {field}") + require(session["mode"] in {"visible", "headless"}, "invalid session mode") + require(session["credentialPosture"] in {"none", "available-but-unused", "used-with-policy", "blocked"}, "invalid credential posture") + + action = data.get("browserActionReceipt") + require(isinstance(action, dict), "browserActionReceipt must be object") + for field in ["actionId", "browserSessionRef", "url", "actionType", "sideEffectClass", "policyDecisionRef", "credentialUse", "resultStatus"]: + require(field in action, f"browserActionReceipt missing {field}") + require(action["policyDecisionRef"], "browser action requires policyDecisionRef") + if action["credentialUse"]: + require(action["sideEffectClass"] == "credential", "credential action must use sideEffectClass=credential") + + download = data.get("browserDownloadReceipt") + require(isinstance(download, dict), "browserDownloadReceipt must be object") + for field in ["downloadId", "sourceUrl", "sha256", "mediaType", "sizeBytes", "quarantineState", "memoryMeshPointerRef", "policyDecisionRef"]: + require(field in download, f"browserDownloadReceipt missing {field}") + require(download["quarantineState"] in {"not-required", "quarantined", "released", "blocked"}, "invalid quarantine state") + + credential = data.get("browserCredentialUseReceipt") + require(isinstance(credential, dict), "browserCredentialUseReceipt must be object") + for field in ["credentialEventId", "browserSessionRef", "credentialScope", "policyDecisionRef", "rawCredentialStored", "resultStatus"]: + require(field in credential, f"browserCredentialUseReceipt missing {field}") + require(credential["rawCredentialStored"] is False, "raw credentials must not be stored") + + +def main() -> int: + try: + if not SCHEMA.exists(): + raise ValidationError(f"missing schema: {SCHEMA}") + data = load_json(EXAMPLE) + validate(data) + except (json.JSONDecodeError, ValidationError) as exc: + print(f"BearBrowser Agent Harness receipt validation failed: {exc}", file=sys.stderr) + return 1 + print("OK: BearBrowser Agent Harness receipt fixture validates") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 0d88b38ea5616229f82a84cca243659efd100a64 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 6 May 2026 20:18:58 -0400 Subject: [PATCH 5/5] Validate agent harness browser receipts in CI --- .../agent-harness-browser-receipts.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/agent-harness-browser-receipts.yml diff --git a/.github/workflows/agent-harness-browser-receipts.yml b/.github/workflows/agent-harness-browser-receipts.yml new file mode 100644 index 0000000..424160c --- /dev/null +++ b/.github/workflows/agent-harness-browser-receipts.yml @@ -0,0 +1,37 @@ +name: Agent Harness Browser Receipts + +on: + pull_request: + paths: + - 'docs/agent-harness-browser-receipts.md' + - 'schemas/agent-harness-browser-receipts.schema.json' + - 'examples/agent-harness-browser-receipts.example.json' + - 'scripts/bearbrowser-verify-agent-harness-receipts.py' + - '.github/workflows/agent-harness-browser-receipts.yml' + push: + branches: + - main + paths: + - 'docs/agent-harness-browser-receipts.md' + - 'schemas/agent-harness-browser-receipts.schema.json' + - 'examples/agent-harness-browser-receipts.example.json' + - 'scripts/bearbrowser-verify-agent-harness-receipts.py' + - '.github/workflows/agent-harness-browser-receipts.yml' + +permissions: + contents: read + +jobs: + validate-agent-harness-browser-receipts: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.x' + + - name: Validate BearBrowser Agent Harness receipts + run: python3 scripts/bearbrowser-verify-agent-harness-receipts.py