From 0bf75bd47413282f52430da18bc1ab79bab6a3a5 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:13:41 -0400 Subject: [PATCH 1/8] docs(spec): add execution-control contract pack placement note --- docs/execution-control-contract-pack-v0.2.md | 52 ++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 docs/execution-control-contract-pack-v0.2.md diff --git a/docs/execution-control-contract-pack-v0.2.md b/docs/execution-control-contract-pack-v0.2.md new file mode 100644 index 0000000..16bb8d6 --- /dev/null +++ b/docs/execution-control-contract-pack-v0.2.md @@ -0,0 +1,52 @@ +# Execution Control Contract Pack v0.2 + +This note captures the first tranche of net-new execution-control contracts for `sourceos-spec`. + +## Why this tranche exists + +The current contract registry already contains nearby execution and agent-plane primitives such as: + +- `WorkflowSpec` +- `RunRecord` +- `SkillManifest` +- `ExecutionDecision` +- `ExecutionSurface` +- `TruthSurface` +- `DeltaSurface` + +To avoid duplicate object classes, this tranche adds only the primitives that do not yet have a clean canonical representation in the spec layer: + +- `ExecutionFork` +- `RoutingContract` +- `CapabilityPolicy` +- `ToolExposurePolicy` +- `QuotaPolicy` +- `RunnerGroup` +- `ProtocolWorkbench` +- `ArtifactDescriptor` + +## Intended reuse map + +- Validation programs continue to profile or extend `WorkflowSpec`. +- Agent skill packaging continues to profile or extend `SkillManifest`. +- Runtime execution receipts continue to profile or extend `RunRecord`. +- Evidence promotion and drift continue to use `TruthSurface` and `DeltaSurface`. + +## Downstream consumers + +These schemas are intended to be consumed by: + +- `SocioProphet/agentplane` +- `SocioProphet/policy-fabric` +- `SocioProphet/TriTRPC` +- `SociOS-Linux/workstation-contracts` +- `SourceOS-Linux/openclaw` +- `SocioProphet/socioprophet-agent-standards` (profile/conformance layer) + +## Follow-on work + +1. Add examples for all new schemas. +2. Update `schemas/README.md`, `examples/README.md`, and root `README.md` schema counts and family tables. +3. Add OpenAPI / AsyncAPI patch entries where the runtime surfaces stabilize. +4. Add derived profiles in `socioprophet-agent-standards`. +5. Wire consumer implementations in `agentplane`, `policy-fabric`, `TriTRPC`, `workstation-contracts`, and `openclaw`. From 71b37b86e028ffc748b5efa3032bc3c9af4a75ca Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:14:32 -0400 Subject: [PATCH 2/8] feat(spec): add ExecutionFork schema --- schemas/ExecutionFork.json | 109 +++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 schemas/ExecutionFork.json diff --git a/schemas/ExecutionFork.json b/schemas/ExecutionFork.json new file mode 100644 index 0000000..3709219 --- /dev/null +++ b/schemas/ExecutionFork.json @@ -0,0 +1,109 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ExecutionFork.json", + "title": "ExecutionFork", + "description": "A delta execution environment that overlays changed workloads, local mappings, and isolation adapters onto a shared baseline. This is the canonical contract for lightweight forked runtime surfaces.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "substrate", "baselineRef", "workloads", "routingContractRef", "cleanupPolicy"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:execution-fork:", + "description": "Stable URN identifier. Pattern: urn:srcos:execution-fork:." + }, + "type": { + "const": "ExecutionFork", + "description": "Discriminator constant — always \"ExecutionFork\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable execution fork name." + }, + "description": { + "type": "string", + "description": "Optional explanation of why the fork exists." + }, + "substrate": { + "type": "string", + "enum": ["kubernetes", "local", "hybrid", "container", "vm"], + "description": "Primary substrate used to realize this fork." + }, + "baselineRef": { + "type": "string", + "description": "Reference to the inherited baseline environment, release, or surface." + }, + "baselineDigest": { + "type": "string", + "description": "Optional digest of the resolved baseline state." + }, + "routingContractRef": { + "type": "string", + "pattern": "^urn:srcos:routing-contract:", + "description": "Routing contract that selects and steers traffic into this fork." + }, + "runnerGroupRef": { + "type": ["string", "null"], + "pattern": "^urn:srcos:runner-group:", + "description": "Optional default runner group for validations executed against this fork." + }, + "capabilityPolicyRef": { + "type": ["string", "null"], + "pattern": "^urn:srcos:capability-policy:", + "description": "Optional governing capability policy for actions inside this fork." + }, + "quotaPolicyRef": { + "type": ["string", "null"], + "pattern": "^urn:srcos:quota:", + "description": "Optional quota policy applied to this fork." + }, + "isolationRefs": { + "type": "array", + "items": { "type": "string" }, + "description": "References to isolation adapters or data partitioning resources used by the fork." + }, + "workloads": { + "type": "array", + "description": "Changed workloads or local overlays attached to the fork.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "targetRef"], + "properties": { + "name": { "type": "string" }, + "targetRef": { "type": "string", "description": "Target workload or service being forked." }, + "imageRef": { "type": ["string", "null"] }, + "localPath": { "type": ["string", "null"] }, + "writePolicy": { + "type": "string", + "enum": ["inherit", "isolated_only", "blocked"], + "description": "Whether writes inherit baseline behavior, remain isolated, or are blocked." + }, + "envOverrides": { + "type": "object", + "additionalProperties": { "type": "string" }, + "description": "Environment overrides to apply for this workload." + } + } + } + }, + "ttl": { + "type": ["string", "null"], + "description": "Advisory lifetime for this fork, e.g. \"8h\"." + }, + "cleanupPolicy": { + "type": "string", + "enum": ["destroy_with_evidence_retained", "destroy_all", "retain_for_debug"], + "description": "Cleanup behavior once the fork expires or is explicitly removed." + }, + "tags": { + "type": "array", + "items": { "type": "string" }, + "description": "Classification tags for actor, mission, trust class, or workflow." + } + } +} \ No newline at end of file From 146d53f11f75cc3c2ed98edc0f694b4577baeb2f Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:18:45 -0400 Subject: [PATCH 3/8] feat(spec): add RoutingContract schema --- schemas/RoutingContract.json | 117 +++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 schemas/RoutingContract.json diff --git a/schemas/RoutingContract.json b/schemas/RoutingContract.json new file mode 100644 index 0000000..5f756db --- /dev/null +++ b/schemas/RoutingContract.json @@ -0,0 +1,117 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/RoutingContract.json", + "title": "RoutingContract", + "description": "A typed routing and propagation contract that selects requests, tool calls, or sessions and directs them toward an execution fork or baseline target under explicit write and fallback semantics.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "targets"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:routing-contract:", + "description": "Stable URN identifier. Pattern: urn:srcos:routing-contract:." + }, + "type": { + "const": "RoutingContract", + "description": "Discriminator constant — always \"RoutingContract\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable routing contract name." + }, + "description": { + "type": "string", + "description": "Optional explanation of the routing contract intent." + }, + "selectors": { + "type": "object", + "additionalProperties": false, + "description": "Selectors that identify traffic or sessions governed by this contract.", + "properties": { + "headers": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "op", "value"], + "properties": { + "name": { "type": "string" }, + "op": { "type": "string", "enum": ["equals", "contains", "prefix"] }, + "value": { "type": "string" } + } + } + }, + "baggage": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "op", "value"], + "properties": { + "name": { "type": "string" }, + "op": { "type": "string", "enum": ["equals", "contains", "prefix"] }, + "value": { "type": "string" } + } + } + }, + "actorRef": { "type": ["string", "null"] }, + "branchRef": { "type": ["string", "null"] }, + "missionRef": { "type": ["string", "null"] }, + "trustClass": { "type": ["string", "null"] } + } + }, + "targets": { + "type": "array", + "description": "Concrete named routing targets governed by this contract.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["name", "targetRef", "fallback", "writePolicy"], + "properties": { + "name": { "type": "string" }, + "targetRef": { "type": "string", "description": "Workload, service, or endpoint reference." }, + "port": { "type": ["integer", "null"], "minimum": 1, "maximum": 65535 }, + "fallback": { + "type": "string", + "enum": ["baseline", "deny"], + "description": "Fallback behavior when the target is unavailable or the selector does not match." + }, + "writePolicy": { + "type": "string", + "enum": ["inherit", "isolated_only", "blocked"], + "description": "How writes are handled for traffic routed through this target." + } + } + } + }, + "propagation": { + "type": "object", + "additionalProperties": false, + "description": "Context propagation rules applied when traffic is routed under this contract.", + "properties": { + "traceContext": { "type": "string", "enum": ["w3c", "b3", "none"] }, + "extraHeaders": { + "type": "array", + "items": { "type": "string" } + } + } + }, + "defaultDeny": { + "type": "boolean", + "description": "Whether unmatched traffic should be denied by default." + }, + "requireCapabilityToken": { + "type": "boolean", + "description": "Whether traffic or session entry under this contract requires a governing capability token." + }, + "readOnlySurface": { + "type": "boolean", + "description": "Whether this routing contract exposes a read-only interaction surface." + } + } +} \ No newline at end of file From 6d4d14d4292a466a7cc570cf9e5d9feb9f9264e7 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Wed, 15 Apr 2026 21:19:23 -0400 Subject: [PATCH 4/8] feat(spec): add CapabilityPolicy schema --- schemas/CapabilityPolicy.json | 86 +++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 schemas/CapabilityPolicy.json diff --git a/schemas/CapabilityPolicy.json b/schemas/CapabilityPolicy.json new file mode 100644 index 0000000..7f4c125 --- /dev/null +++ b/schemas/CapabilityPolicy.json @@ -0,0 +1,86 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/CapabilityPolicy.json", + "title": "CapabilityPolicy", + "description": "A typed capability authorization policy for execution forks, protocols, tools, and runtime primitives. This is the canonical allow/deny surface below which tool exposure policies may only reduce visibility, never widen authority.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "version", "defaultEffect", "grants"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:capability-policy:", + "description": "Stable URN identifier. Pattern: urn:srcos:capability-policy:." + }, + "type": { + "const": "CapabilityPolicy", + "description": "Discriminator constant — always \"CapabilityPolicy\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable policy name." + }, + "version": { + "type": "string", + "description": "Semver version of this capability policy." + }, + "description": { + "type": "string", + "description": "Optional explanation of what this policy governs." + }, + "appliesToTransport": { + "type": "array", + "items": { "type": "string", "enum": ["mcp", "tritrpc", "cli", "api", "runtime"] }, + "description": "Transports or invocation surfaces governed by this policy." + }, + "defaultEffect": { + "type": "string", + "enum": ["allow", "deny"], + "description": "Default decision when no grant matches." + }, + "tokenTtlSeconds": { + "type": "integer", + "minimum": 1, + "description": "Optional default token TTL for grants resolved from this policy." + }, + "grants": { + "type": "array", + "description": "Ordered grants evaluated against subjects, capabilities, and optional selectors.", + "items": { + "type": "object", + "additionalProperties": false, + "required": ["effect", "capabilityPrefixes"], + "properties": { + "subjectRefs": { + "type": "array", + "items": { "type": "string" }, + "description": "Explicit subjects, agents, services, or communities this grant applies to." + }, + "effect": { + "type": "string", + "enum": ["allow", "deny"], + "description": "Grant effect." + }, + "capabilityPrefixes": { + "type": "array", + "items": { "type": "string" }, + "description": "Capability prefixes matched by this grant, e.g. net.http or fs.read." + }, + "selectors": { + "type": "object", + "additionalProperties": true, + "description": "Optional workload, mission, repo, or trust-class selectors." + }, + "requireHumanApproval": { + "type": "boolean", + "description": "Whether use of this grant requires explicit human approval." + } + } + } + } + } +} \ No newline at end of file From 078b09158a5ed5a9d8ab761c555fe869eb569cfc Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:44:27 -0400 Subject: [PATCH 5/8] feat(spec): add ToolExposurePolicy schema --- schemas/ToolExposurePolicy.json | 78 +++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 schemas/ToolExposurePolicy.json diff --git a/schemas/ToolExposurePolicy.json b/schemas/ToolExposurePolicy.json new file mode 100644 index 0000000..ee8114b --- /dev/null +++ b/schemas/ToolExposurePolicy.json @@ -0,0 +1,78 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ToolExposurePolicy.json", + "title": "ToolExposurePolicy", + "description": "A policy describing which tools or toolsets are exposed on a given interaction surface. This policy can only reduce or reshape visibility relative to an underlying CapabilityPolicy; it cannot grant new authority.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "version", "transport", "exposureMode"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:tool-exposure:", + "description": "Stable URN identifier. Pattern: urn:srcos:tool-exposure:." + }, + "type": { + "const": "ToolExposurePolicy", + "description": "Discriminator constant — always \"ToolExposurePolicy\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable policy name." + }, + "version": { + "type": "string", + "description": "Semver version of this exposure policy." + }, + "transport": { + "type": "string", + "enum": ["mcp", "tritrpc", "cli", "api"], + "description": "Transport or invocation surface this policy governs." + }, + "exposureMode": { + "type": "string", + "enum": ["full", "read_only", "allow_list", "deny_list", "consent_gated"], + "description": "How tool visibility is reduced or curated." + }, + "capabilityPolicyRef": { + "type": ["string", "null"], + "pattern": "^urn:srcos:capability-policy:", + "description": "Optional governing capability policy this visibility policy reduces against." + }, + "defaultToolsets": { + "type": "array", + "items": { + "type": "string", + "enum": ["sandboxes", "routegroups", "clusters", "workloads", "resources", "devboxes", "plans", "runs", "artifacts", "help"] + }, + "description": "Named default toolsets enabled before explicit include/exclude reduction." + }, + "includeTools": { + "type": "array", + "items": { "type": "string" }, + "description": "Explicit tool allow-list applied after toolset resolution." + }, + "excludeTools": { + "type": "array", + "items": { "type": "string" }, + "description": "Explicit tool deny-list applied after include resolution." + }, + "requireMutationConsent": { + "type": "boolean", + "description": "Whether mutating tools require explicit runtime consent." + }, + "sensitiveDataMode": { + "type": "string", + "enum": ["blocked", "redacted", "allowed"], + "description": "Whether sensitive tool outputs are blocked, redacted, or fully allowed." + }, + "lockdownMode": { + "type": "boolean", + "description": "Whether tool results should be constrained to trusted or locally governed sources." + } + } +} \ No newline at end of file From c538c070dabced9d55218a7ac8e0b498031b4e93 Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:52:14 -0400 Subject: [PATCH 6/8] feat(spec): add QuotaPolicy schema --- schemas/QuotaPolicy.json | 75 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 schemas/QuotaPolicy.json diff --git a/schemas/QuotaPolicy.json b/schemas/QuotaPolicy.json new file mode 100644 index 0000000..33f53c9 --- /dev/null +++ b/schemas/QuotaPolicy.json @@ -0,0 +1,75 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/QuotaPolicy.json", + "title": "QuotaPolicy", + "description": "A typed quota and resource allocation policy for execution forks, runs, protocol workbenches, and artifact retention windows across organizations, teams, actors, missions, or environment classes.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "version", "scope", "limits", "behaviorOnExceed"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:quota:", + "description": "Stable URN identifier. Pattern: urn:srcos:quota:." + }, + "type": { + "const": "QuotaPolicy", + "description": "Discriminator constant — always \"QuotaPolicy\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable quota policy name." + }, + "version": { + "type": "string", + "description": "Semver version of this quota policy." + }, + "scope": { + "type": "string", + "enum": ["organization", "team", "actor", "mission", "repo", "environment_class"], + "description": "Primary scope dimension this quota applies to." + }, + "selectors": { + "type": "object", + "additionalProperties": true, + "description": "Optional selectors used to refine the quota scope." + }, + "limits": { + "type": "object", + "additionalProperties": false, + "properties": { + "sandboxesCreatedPerWindow": { "type": "integer", "minimum": 0 }, + "concurrentExecutionForks": { "type": "integer", "minimum": 0 }, + "concurrentProtocolWorkbenches": { "type": "integer", "minimum": 0 }, + "concurrentGovernedRuns": { "type": "integer", "minimum": 0 }, + "testInvocationsPerWindow": { "type": "integer", "minimum": 0 }, + "artifactStorageBytes": { "type": "integer", "minimum": 0 }, + "logRetentionHours": { "type": "integer", "minimum": 1 } + }, + "description": "Concrete numerical limits enforced by this quota policy." + }, + "window": { + "type": "object", + "additionalProperties": false, + "properties": { + "unit": { "type": "string", "enum": ["hour", "day", "week", "month"] }, + "value": { "type": "integer", "minimum": 1 } + }, + "description": "Accounting window for per-window limits." + }, + "behaviorOnExceed": { + "type": "string", + "enum": ["reject", "queue", "degrade_read_only", "require_human_approval"], + "description": "Behavior when limits are exceeded." + }, + "accountingMode": { + "type": "string", + "enum": ["admission_only", "admission_and_runtime"], + "description": "Whether quota accounting applies only at admission time or throughout runtime as well." + } + } +} \ No newline at end of file From a75dbb27c45690dffdc6bc5fee334a66fde75b7b Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Mon, 20 Apr 2026 18:53:55 -0400 Subject: [PATCH 7/8] feat(spec): add RunnerGroup schema --- schemas/RunnerGroup.json | 74 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 schemas/RunnerGroup.json diff --git a/schemas/RunnerGroup.json b/schemas/RunnerGroup.json new file mode 100644 index 0000000..8850b1e --- /dev/null +++ b/schemas/RunnerGroup.json @@ -0,0 +1,74 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/RunnerGroup.json", + "title": "RunnerGroup", + "description": "A versioned runtime bundle that supplies pinned images, built-in primitives, custom primitive extensions, and execution defaults for validations or protocol workbenches.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "version", "runtime", "imageRef", "imageDigestPinned"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:runner-group:", + "description": "Stable URN identifier. Pattern: urn:srcos:runner-group:." + }, + "type": { + "const": "RunnerGroup", + "description": "Discriminator constant — always \"RunnerGroup\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable runner group name." + }, + "version": { + "type": "string", + "description": "Semver version of this runner group." + }, + "runtime": { + "type": "string", + "enum": ["container", "wasm", "local", "hybrid"], + "description": "Primary execution runtime used by the runner group." + }, + "imageRef": { + "type": "string", + "description": "Pinned image or runtime artifact reference used by this runner group." + }, + "imageDigestPinned": { + "type": "boolean", + "description": "Whether the image or artifact reference is digest-pinned." + }, + "builtInPrimitives": { + "type": "array", + "items": { "type": "string" }, + "description": "Primitive names bundled with this runner group." + }, + "customPrimitiveRefs": { + "type": "array", + "items": { "type": "string" }, + "description": "References to custom primitive definitions or external bundles." + }, + "dependencyProfiles": { + "type": "array", + "items": { "type": "string" }, + "description": "Dependency profile names loaded by the runner group." + }, + "networkPolicyRef": { + "type": ["string", "null"], + "description": "Optional network policy applied to the runner environment." + }, + "filesystemPolicy": { + "type": "string", + "enum": ["ephemeral", "retained", "read_only_base"], + "description": "Filesystem semantics for runner execution." + }, + "cachePolicy": { + "type": "string", + "enum": ["none", "ephemeral", "shared_read_only"], + "description": "Cache behavior for repeated executions." + } + } +} \ No newline at end of file From 0d6f7f706248e323522768c06e69a9c1277bcb4e Mon Sep 17 00:00:00 2001 From: mdheller <21163552+mdheller@users.noreply.github.com> Date: Tue, 21 Apr 2026 23:21:09 -0400 Subject: [PATCH 8/8] feat(spec): add ProtocolWorkbench schema --- schemas/ProtocolWorkbench.json | 84 ++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 schemas/ProtocolWorkbench.json diff --git a/schemas/ProtocolWorkbench.json b/schemas/ProtocolWorkbench.json new file mode 100644 index 0000000..1895d41 --- /dev/null +++ b/schemas/ProtocolWorkbench.json @@ -0,0 +1,84 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://schemas.srcos.ai/v2/ProtocolWorkbench.json", + "title": "ProtocolWorkbench", + "description": "A typed workbench for developing, testing, and validating protocol-facing servers such as MCP, TriTRPC, HTTP APIs, gRPC services, or A2A endpoints against an execution fork.", + "type": "object", + "additionalProperties": false, + "required": ["id", "type", "specVersion", "name", "protocol", "executionForkRef", "serverUnderTest"], + "properties": { + "id": { + "type": "string", + "pattern": "^urn:srcos:workbench:", + "description": "Stable URN identifier. Pattern: urn:srcos:workbench:." + }, + "type": { + "const": "ProtocolWorkbench", + "description": "Discriminator constant — always \"ProtocolWorkbench\"." + }, + "specVersion": { + "type": "string", + "description": "Spec version of this document, e.g. \"2.0.0\"." + }, + "name": { + "type": "string", + "description": "Human-readable protocol workbench name." + }, + "protocol": { + "type": "string", + "enum": ["mcp", "a2a", "tritrpc", "http_api", "grpc"], + "description": "Primary protocol surface under test." + }, + "executionForkRef": { + "type": "string", + "pattern": "^urn:srcos:execution-fork:", + "description": "Execution fork used to host or exercise the server under test." + }, + "routingContractRef": { + "type": ["string", "null"], + "pattern": "^urn:srcos:routing-contract:", + "description": "Optional routing contract used by the workbench." + }, + "serverUnderTest": { + "type": "object", + "additionalProperties": false, + "required": ["entrypoint"], + "properties": { + "entrypoint": { "type": "string", "description": "Entrypoint, command, or service reference for the server under test." }, + "localMapping": { "type": "boolean", "description": "Whether the server under test is mapped from a local workstation path or process." }, + "previewUrlEnabled": { "type": "boolean", "description": "Whether the workbench emits a preview URL for human review." } + } + }, + "clientProfiles": { + "type": "array", + "items": { "type": "string" }, + "description": "Named client profiles used to exercise the server under test." + }, + "trafficCapture": { + "type": "object", + "additionalProperties": false, + "properties": { + "captureRequests": { "type": "boolean" }, + "captureResponses": { "type": "boolean" }, + "captureToolCalls": { "type": "boolean" }, + "redactSensitiveFields": { "type": "boolean" } + }, + "description": "Traffic and transcript capture settings for the workbench." + }, + "transcriptMode": { + "type": "string", + "enum": ["request_response", "tool_call", "mixed"], + "description": "Transcript style emitted by this workbench." + }, + "validationRefs": { + "type": "array", + "items": { "type": "string" }, + "description": "References to workflows, skills, or validation bundles exercised by this workbench." + }, + "artifactClasses": { + "type": "array", + "items": { "type": "string", "enum": ["transcript", "screenshot", "request_log", "response_log", "schema_diff", "tool_trace", "preview_link"] }, + "description": "Artifact classes expected from this workbench." + } + } +} \ No newline at end of file