From 8e1b49d72090321b0417999db7a024e5d32a987a Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 23 May 2026 10:39:42 -0400 Subject: [PATCH 1/5] Replay agent harness terminal receipt workflow --- .../agent-harness-terminal-receipts.yml | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 .github/workflows/agent-harness-terminal-receipts.yml diff --git a/.github/workflows/agent-harness-terminal-receipts.yml b/.github/workflows/agent-harness-terminal-receipts.yml new file mode 100644 index 00000000000..431ad888c9e --- /dev/null +++ b/.github/workflows/agent-harness-terminal-receipts.yml @@ -0,0 +1,37 @@ +name: Agent Harness Terminal Receipts + +on: + pull_request: + paths: + - 'docs/sourceos/AGENT_HARNESS_TERMINAL_RECEIPTS.md' + - 'schemas/agent-harness-terminal-receipts.schema.json' + - 'examples/agent-harness-terminal-receipts.example.json' + - 'scripts/verify-agent-harness-terminal-receipts.py' + - '.github/workflows/agent-harness-terminal-receipts.yml' + push: + branches: + - main + paths: + - 'docs/sourceos/AGENT_HARNESS_TERMINAL_RECEIPTS.md' + - 'schemas/agent-harness-terminal-receipts.schema.json' + - 'examples/agent-harness-terminal-receipts.example.json' + - 'scripts/verify-agent-harness-terminal-receipts.py' + - '.github/workflows/agent-harness-terminal-receipts.yml' + +permissions: + contents: read + +jobs: + validate-agent-harness-terminal-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 TurtleTerm Agent Harness receipts + run: python3 scripts/verify-agent-harness-terminal-receipts.py From 64e859b98f797fc3380f4a4e5b96dacdcc42df25 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 23 May 2026 10:41:13 -0400 Subject: [PATCH 2/5] Replay agent harness terminal receipt example --- ...ent-harness-terminal-receipts.example.json | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 examples/agent-harness-terminal-receipts.example.json diff --git a/examples/agent-harness-terminal-receipts.example.json b/examples/agent-harness-terminal-receipts.example.json new file mode 100644 index 00000000000..5d4b45edd9b --- /dev/null +++ b/examples/agent-harness-terminal-receipts.example.json @@ -0,0 +1,50 @@ +{ + "schemaVersion": "v0.1", + "kind": "AgentHarnessTerminalReceipts", + "terminalSessionReceipt": { + "sessionId": "turtleterm-session-agent-harness-v0.1", + "actorRef": "github://mdheller", + "workspaceRef": "github://SocioProphet/sociosphere", + "shellProfile": "sourceos-local-dev", + "gatewayProfile": "turtle-agentd-local", + "policyAdmissionRef": "github://SocioProphet/policy-fabric/pull/60", + "agentplaneRunRef": "github://SocioProphet/agentplane/pull/107", + "muxPaneRefs": [], + "environmentProfileHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111" + }, + "commandReceipt": { + "commandId": "command-agent-harness-validate-runtime-contracts", + "terminalSessionRef": "turtleterm-session-agent-harness-v0.1", + "commandHash": "sha256:2222222222222222222222222222222222222222222222222222222222222222", + "workingDirectory": "~/dev/agentplane", + "environmentProfileHash": "sha256:1111111111111111111111111111111111111111111111111111111111111111", + "stdoutPointerRef": "artifact://sha256/3333333333333333333333333333333333333333333333333333333333333333", + "stderrPointerRef": "artifact://sha256/4444444444444444444444444444444444444444444444444444444444444444", + "exitCode": 0, + "policyDecisionRef": "github://SocioProphet/policy-fabric/pull/60", + "sideEffectClass": "none", + "replayEligible": true + }, + "mutationReceipt": { + "mutationId": "mutation-none-agent-harness-v0.1", + "commandRef": "command-agent-harness-validate-runtime-contracts", + "mutationClass": "none", + "targetScope": "workspace-only", + "mode": "dry-run", + "policyDecisionRef": "github://SocioProphet/policy-fabric/pull/60", + "humanControlEventRef": "", + "rollbackRef": "", + "mutatedHost": false, + "deniedOperationRefs": [] + }, + "operatorApprovalReceipt": { + "approvalId": "operator-approval-agent-harness-baseline", + "actorRef": "github://mdheller", + "subjectRef": "github://SourceOS-Linux/TurtleTerm/pull/5", + "decision": "deferred", + "reason": "Baseline receipt fixture only; live terminal mutation approval is not requested.", + "policyGateRef": "github://SocioProphet/policy-fabric/pull/60", + "agentplaneRunRef": "github://SocioProphet/agentplane/pull/107", + "deliveryExcellenceEventRef": "github://SocioProphet/delivery-excellence-automation/pull/7" + } +} From b8bf7fa05693cb7b6d62bb3e39253fd654edbed7 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 23 May 2026 10:44:04 -0400 Subject: [PATCH 3/5] Replay agent harness terminal receipt schema --- ...gent-harness-terminal-receipts.schema.json | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 schemas/agent-harness-terminal-receipts.schema.json diff --git a/schemas/agent-harness-terminal-receipts.schema.json b/schemas/agent-harness-terminal-receipts.schema.json new file mode 100644 index 00000000000..e9966dfb03c --- /dev/null +++ b/schemas/agent-harness-terminal-receipts.schema.json @@ -0,0 +1,78 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://sourceos.dev/schemas/turtleterm/agent-harness-terminal-receipts.schema.json", + "title": "AgentHarnessTerminalReceipts", + "type": "object", + "additionalProperties": false, + "required": ["schemaVersion", "kind", "terminalSessionReceipt", "commandReceipt", "mutationReceipt", "operatorApprovalReceipt"], + "properties": { + "schemaVersion": { "const": "v0.1" }, + "kind": { "const": "AgentHarnessTerminalReceipts" }, + "terminalSessionReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["sessionId", "actorRef", "workspaceRef", "shellProfile", "gatewayProfile", "policyAdmissionRef", "agentplaneRunRef", "environmentProfileHash"], + "properties": { + "sessionId": { "type": "string" }, + "actorRef": { "type": "string" }, + "workspaceRef": { "type": "string" }, + "shellProfile": { "type": "string" }, + "gatewayProfile": { "type": "string" }, + "policyAdmissionRef": { "type": "string" }, + "agentplaneRunRef": { "type": "string" }, + "muxPaneRefs": { "type": "array", "items": { "type": "string" } }, + "environmentProfileHash": { "type": "string" } + } + }, + "commandReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["commandId", "terminalSessionRef", "commandHash", "workingDirectory", "environmentProfileHash", "exitCode", "policyDecisionRef", "sideEffectClass", "replayEligible"], + "properties": { + "commandId": { "type": "string" }, + "terminalSessionRef": { "type": "string" }, + "commandHash": { "type": "string" }, + "workingDirectory": { "type": "string" }, + "environmentProfileHash": { "type": "string" }, + "stdoutPointerRef": { "type": "string" }, + "stderrPointerRef": { "type": "string" }, + "exitCode": { "type": "integer" }, + "policyDecisionRef": { "type": "string" }, + "sideEffectClass": { "type": "string", "enum": ["none", "workspace-write", "host-mutation", "secret-access", "network-service", "deployment"] }, + "replayEligible": { "type": "boolean" } + } + }, + "mutationReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["mutationId", "commandRef", "mutationClass", "targetScope", "mode", "policyDecisionRef", "mutatedHost"], + "properties": { + "mutationId": { "type": "string" }, + "commandRef": { "type": "string" }, + "mutationClass": { "type": "string" }, + "targetScope": { "type": "string" }, + "mode": { "type": "string", "enum": ["dry-run", "live"] }, + "policyDecisionRef": { "type": "string" }, + "humanControlEventRef": { "type": "string" }, + "rollbackRef": { "type": "string" }, + "mutatedHost": { "type": "boolean" }, + "deniedOperationRefs": { "type": "array", "items": { "type": "string" } } + } + }, + "operatorApprovalReceipt": { + "type": "object", + "additionalProperties": false, + "required": ["approvalId", "actorRef", "subjectRef", "decision", "policyGateRef", "agentplaneRunRef", "deliveryExcellenceEventRef"], + "properties": { + "approvalId": { "type": "string" }, + "actorRef": { "type": "string" }, + "subjectRef": { "type": "string" }, + "decision": { "type": "string", "enum": ["approved", "rejected", "deferred", "accepted-risk", "revoked"] }, + "reason": { "type": "string" }, + "policyGateRef": { "type": "string" }, + "agentplaneRunRef": { "type": "string" }, + "deliveryExcellenceEventRef": { "type": "string" } + } + } + } +} From cfe178399f8426a4e6ed8c8981a40333663d7941 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 23 May 2026 10:46:44 -0400 Subject: [PATCH 4/5] Replay agent harness terminal receipt verifier --- .../verify-agent-harness-terminal-receipts.py | 78 +++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 scripts/verify-agent-harness-terminal-receipts.py diff --git a/scripts/verify-agent-harness-terminal-receipts.py b/scripts/verify-agent-harness-terminal-receipts.py new file mode 100644 index 00000000000..f7973db7446 --- /dev/null +++ b/scripts/verify-agent-harness-terminal-receipts.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 +"""Verify TurtleTerm Agent Harness terminal 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-terminal-receipts.schema.json" +EXAMPLE = ROOT / "examples" / "agent-harness-terminal-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(SCHEMA.exists(), f"missing schema: {SCHEMA}") + require(data.get("schemaVersion") == "v0.1", "schemaVersion must be v0.1") + require(data.get("kind") == "AgentHarnessTerminalReceipts", "kind mismatch") + + session = data.get("terminalSessionReceipt") + require(isinstance(session, dict), "terminalSessionReceipt must be object") + for field in ["sessionId", "actorRef", "workspaceRef", "shellProfile", "gatewayProfile", "policyAdmissionRef", "agentplaneRunRef", "environmentProfileHash"]: + require(field in session, f"terminalSessionReceipt missing {field}") + require(session["environmentProfileHash"].startswith("sha256:"), "environmentProfileHash must be a sha256 ref") + + command = data.get("commandReceipt") + require(isinstance(command, dict), "commandReceipt must be object") + for field in ["commandId", "terminalSessionRef", "commandHash", "workingDirectory", "environmentProfileHash", "exitCode", "policyDecisionRef", "sideEffectClass", "replayEligible"]: + require(field in command, f"commandReceipt missing {field}") + require(command["commandHash"].startswith("sha256:"), "commandHash must be a sha256 ref") + require(command["policyDecisionRef"], "commandReceipt requires policyDecisionRef") + if command["exitCode"] != 0: + require(command["replayEligible"] is False, "failed command should not be replayEligible in baseline fixture") + + mutation = data.get("mutationReceipt") + require(isinstance(mutation, dict), "mutationReceipt must be object") + for field in ["mutationId", "commandRef", "mutationClass", "targetScope", "mode", "policyDecisionRef", "mutatedHost"]: + require(field in mutation, f"mutationReceipt missing {field}") + require(mutation["mode"] in {"dry-run", "live"}, "invalid mutation mode") + if mutation["mutatedHost"]: + require(mutation["mode"] == "live", "mutatedHost=true requires mode=live") + require(mutation.get("humanControlEventRef"), "live host mutation requires human control event ref") + + approval = data.get("operatorApprovalReceipt") + require(isinstance(approval, dict), "operatorApprovalReceipt must be object") + for field in ["approvalId", "actorRef", "subjectRef", "decision", "policyGateRef", "agentplaneRunRef", "deliveryExcellenceEventRef"]: + require(field in approval, f"operatorApprovalReceipt missing {field}") + require(approval["decision"] in {"approved", "rejected", "deferred", "accepted-risk", "revoked"}, "invalid operator decision") + + +def main() -> int: + try: + data = load_json(EXAMPLE) + validate(data) + except (json.JSONDecodeError, ValidationError) as exc: + print(f"TurtleTerm Agent Harness receipt validation failed: {exc}", file=sys.stderr) + return 1 + print("OK: TurtleTerm Agent Harness receipt fixture validates") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) From 9728a897cc2b2b1af61c9bc04331b8e2f5bea806 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Sat, 23 May 2026 10:53:40 -0400 Subject: [PATCH 5/5] Replay agent harness terminal receipt documentation --- .../AGENT_HARNESS_TERMINAL_RECEIPTS.md | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 docs/sourceos/AGENT_HARNESS_TERMINAL_RECEIPTS.md diff --git a/docs/sourceos/AGENT_HARNESS_TERMINAL_RECEIPTS.md b/docs/sourceos/AGENT_HARNESS_TERMINAL_RECEIPTS.md new file mode 100644 index 00000000000..fa03662a66f --- /dev/null +++ b/docs/sourceos/AGENT_HARNESS_TERMINAL_RECEIPTS.md @@ -0,0 +1,53 @@ +# Agent Harness Terminal Receipt Surface + +Status: v0.1 planning baseline +Owner plane: TurtleTerm governed operator surface +Consumers: SourceOS spec, AgentPlane, Policy Fabric, Memory Mesh, SCOPE-D, Delivery Excellence + +## Purpose + +This document defines the TurtleTerm receipt boundary for agent-harness operator work. The surface is intended to make sessions visible, bounded, policy-referenced, and replayable without assigning independent authority to agents or cognition layers. + +## Boundary + +TurtleTerm owns the local operator experience, wrapper receipts, approval receipts, pane references, local gateway evidence, and replayable workflow records. + +TurtleTerm does not own AgentPlane graph execution, Policy Fabric authority decisions, Agent Machine provider lifecycle, Delivery Excellence scoreboards, Memory Mesh artifact storage, or SCOPE-D exercise execution. + +## Receipt classes + +TerminalSessionReceipt records a governed session with session id, actor ref, workspace ref, profile refs, policy admission ref, AgentPlane refs, timestamps, pane refs when applicable, and environment profile hash. + +CommandReceipt records an execution event with event id, session ref, event hash, working directory, environment hash, artifact pointer refs, exit code, duration, policy decision ref, side-effect class, and replay eligibility. + +MutationReceipt records an observed change with change id, execution ref, change class, target scope, run mode, policy decision ref, human-control event ref when required, before and after artifact refs when available, rollback ref, and denied operation refs. + +OperatorApprovalReceipt records a typed human decision with approval id, actor ref, subject ref, decision, reason, timestamp, policy gate ref, AgentPlane ref, and Delivery Excellence human-control event ref. + +## Integration notes + +AgentPlane should cite TurtleTerm receipts in run, replay, session, evidence, diagnosis, and promotion surfaces. + +Large outputs, transcripts, generated files, diffs, and local artifacts should be represented through Memory Mesh ArtifactPointer refs when large, sensitive, replay-critical, or customer-proof relevant. + +Delivery Excellence should consume derived readouts such as success or failure, policy-blocked counts, change posture, approval latency, replay eligibility, operator intervention count, workflow cycle time, and customer-safe proof of work. It should not consume raw local transcripts unless policy permits it. + +SCOPE-D should validate the governed-workflow boundary and provide checks that the policy reference model is preserved. + +## Non-negotiables + +- TurtleTerm must not grant ambient authority to agents. +- Agent Machine owns machine-local provider lifecycle. +- Policy Fabric decides controlled action authority. +- Outputs may require redaction and artifact pointers. +- Host-level changes must be explicit, policy-referenced, and rollback-aware. +- Human approvals are typed control events, not freeform notes. +- Delivery Excellence receives metrics and readouts, not uncontrolled raw logs. + +## Near-term implementation path + +1. Align wrapper receipts with SourceOS execution receipt boundaries. +2. Add examples for session, execution, change, and approval receipts. +3. Add a verifier requiring policy refs for controlled action classes. +4. Add Delivery Excellence projection examples. +5. Add SCOPE-D boundary checks for the governed operator workflow.