Skip to content
Draft
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
34 changes: 34 additions & 0 deletions .github/workflows/workspace-ops.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: workspace-ops

on:
pull_request:
paths:
- 'schemas/workspace-operation-state.schema.json'
- 'schemas/operation-command.schema.json'
- 'schemas/diagnostics-export.schema.json'
- 'examples/workspace-ops/**'
- 'scripts/validate_workspace_ops.py'
- '.github/workflows/workspace-ops.yml'
push:
branches:
- main
- copilot/expose-local-workspace-operations
paths:
- 'schemas/workspace-operation-state.schema.json'
- 'schemas/operation-command.schema.json'
- 'schemas/diagnostics-export.schema.json'
- 'examples/workspace-ops/**'
- 'scripts/validate_workspace_ops.py'
- '.github/workflows/workspace-ops.yml'
workflow_dispatch:

jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python -m pip install jsonschema
- run: python scripts/validate_workspace_ops.py
109 changes: 109 additions & 0 deletions docs/workspace-operations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
# Workspace Operations Contract

Status: initial contract-capture slice.

`sourceos-shell` is the SourceOS shell and user-interface plane. This document
defines how the shell surfaces and controls local Workspace Operations — sync,
terminal, browser, local agent-machine, model carry, and workstation state —
without becoming a runtime or policy authority.

## Boundary

The shell is a **control surface and projection layer**. It must not create
hidden mutations or policy decisions outside the Operation Plane.

- The shell reads operation/task state from contracts supplied by the Operation
Plane; it does not author that state.
- The shell routes actions through structured `OperationCommand` records; it
does not execute integrations directly.
- The shell applies redaction policy before emitting diagnostics exports; it
does not decide that policy.

## Required surfaces

| Surface | Description |
|---|---|
| Local Operation Tray projection | `operationTrayProjection` in `WorkspaceOperationState` |
| Local Operation Inspector projection | `operationInspectorProjection` in `WorkspaceOperationState` |
| File availability states | `fileAvailabilityState`: `local`, `remote`, `syncing`, `conflicted`, `quarantined` |
| Device identity / trust profile | `deviceIdentity` in `WorkspaceOperationState` |
| Sync status from `sourceos-syncd` | `syncStatus` in `WorkspaceOperationState` |
| TurtleTerm entry point | `integrationEntryPoints.turtleTerm` + `OperationCommand` class `turtleterm-open` / `turtleterm-close` |
| BearBrowser entry point | `integrationEntryPoints.bearBrowser` + `OperationCommand` class `bearbrowser-open` / `bearbrowser-close` |
| Agent-machine entry point | `integrationEntryPoints.agentMachine` + `OperationCommand` class `agentmachine-activate` / `agentmachine-deactivate` |
| Redacted diagnostics export | `DiagnosticsExport` schema with `redactionApplied: true` |

## Operation states

The shell must be able to distinguish all of the following `operationState`
values as reported by the Operation Plane:

| State | Meaning |
|---|---|
| `stored` | Operation received and stored; not yet admitted |
| `quarantined` | Operation held pending policy review |
| `admitted` | Operation admitted to the active workspace |
| `activated` | Operation is running |
| `syncing` | Operation is being synchronised with remote |
| `conflicted` | Operation has a merge or sync conflict |
| `failed` | Operation terminated with an error |

## File availability states

| State | Meaning |
|---|---|
| `local` | File is locally available |
| `remote` | File exists only on remote |
| `syncing` | File is being synchronised |
| `conflicted` | File has a sync or merge conflict |
| `quarantined` | File is held pending policy review |

## OperationCommand routing

Shell actions route through `OperationCommand` records
(`schemas/operation-command.schema.json`). The shell emits a command record
with a `commandClass` such as `turtleterm-open`, `sync-request`, or
`diagnostics-export`; the Operation Plane acts on it.

Supported command classes:

- `turtleterm-open` / `turtleterm-close`
- `bearbrowser-open` / `bearbrowser-close`
- `agentmachine-activate` / `agentmachine-deactivate`
- `sync-request` / `sync-cancel`
- `diagnostics-export`
- `model-carry-initiate`
- `workstation-state-query`

All commands support `isDryRun: true` for plan/preview without side effects.

## Diagnostics export

The `DiagnosticsExport` schema (`schemas/diagnostics-export.schema.json`)
enforces:

- `redactionApplied: true` — redaction is always applied before export.
- `contentCaptureEnabled: false` — inline content capture is always disabled.
- `payloadMode` — must be `metadata-only`, `summary`, `ref-only`, or
`redacted`.
- `policyDecisionRefs` — non-empty; Policy Fabric decision refs are required.

## Required integrations

- `SourceOS-Linux/sourceos-spec#87`
- `SociOS-Linux/workstation-contracts#28`
- `SourceOS-Linux/sourceos-syncd#3`
- `SourceOS-Linux/sourceos-devtools#19`
- `SourceOS-Linux/BearBrowser#20`
- `SourceOS-Linux/agent-machine#18`
- `SocioProphet/prophet-core-contracts#1`
- `SocioProphet/sociosphere#259`

## Non-goals

- Shell does not own Policy Fabric or Operation Plane runtime logic.
- Shell does not create hidden mutations outside the Operation Plane.
- Shell does not enable content capture.
- Shell does not export diagnostics without Policy Fabric decision refs.
- Shell does not activate agent-machine integrations without Agent Registry
authority.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"exportId": "urn:srcos:diag-export:summary-demo-0001",
"specVersion": "0.1.0",
"exportedAt": "2026-05-07T06:11:00Z",
"actorRef": "urn:srcos:subject:operator-demo",
"sessionRef": "urn:srcos:shell-session:demo-0002",
"workspaceRef": "urn:srcos:workspace:professional-intelligence-demo",
"redactionApplied": true,
"payloadMode": "metadata-only",
"contentCaptureEnabled": false,
"diagnosticClasses": [
"operation-state",
"sync-status",
"device-identity",
"integration-entry-point"
],
"artifactRefs": [
"urn:srcos:evidence:diag-export-summary-demo-0001"
],
"redactionRefs": [],
"policyDecisionRefs": [
"urn:srcos:policy-decision:diag-export-summary-demo-0001"
]
}
23 changes: 23 additions & 0 deletions examples/workspace-ops/diagnostics-export.redacted.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"exportId": "urn:srcos:diag-export:redacted-demo-0001",
"specVersion": "0.1.0",
"exportedAt": "2026-05-07T06:10:00Z",
"actorRef": "urn:srcos:subject:operator-demo",
"sessionRef": "urn:srcos:shell-session:demo-0001",
"workspaceRef": "urn:srcos:workspace:professional-intelligence-demo",
"redactionApplied": true,
"payloadMode": "redacted",
"contentCaptureEnabled": false,
"diagnosticClasses": [
"operation-state",
"sync-status",
"file-availability"
],
"artifactRefs": [],
"redactionRefs": [
"urn:srcos:redaction-tombstone:diag-export-demo-credential-boundary-0001"
],
"policyDecisionRefs": [
"urn:srcos:policy-decision:diag-export-demo-0001"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"commandId": "urn:srcos:op-command:agentmachine-activate-demo-0001",
"specVersion": "0.1.0",
"issuedAt": "2026-05-07T06:07:00Z",
"actorRef": "urn:srcos:subject:operator-demo",
"sessionRef": "urn:srcos:shell-session:demo-0001",
"commandClass": "agentmachine-activate",
"targetRef": "urn:srcos:workspace-op-state:admitted-syncing-demo-0001",
"payload": {
"agentRegistryRef": "urn:srcos:agent-grant:ops-history-operator-assist-demo",
"inlineMaterialIncluded": false
},
"isDryRun": false,
"policyDecisionRefs": [
"urn:srcos:policy-decision:op-command-agentmachine-demo-0001"
]
}
17 changes: 17 additions & 0 deletions examples/workspace-ops/operation-command.sync-request.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"commandId": "urn:srcos:op-command:sync-request-demo-0001",
"specVersion": "0.1.0",
"issuedAt": "2026-05-07T06:06:00Z",
"actorRef": "urn:srcos:subject:operator-demo",
"sessionRef": "urn:srcos:shell-session:demo-0001",
"commandClass": "sync-request",
"targetRef": "urn:srcos:workspace:professional-intelligence-demo",
"payload": {
"syncProfileRef": "urn:srcos:sync-profile:default",
"inlineMaterialIncluded": false
},
"isDryRun": true,
"policyDecisionRefs": [
"urn:srcos:policy-decision:op-command-sync-demo-0001"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"commandId": "urn:srcos:op-command:turtleterm-open-demo-0001",
"specVersion": "0.1.0",
"issuedAt": "2026-05-07T06:05:00Z",
"actorRef": "urn:srcos:subject:operator-demo",
"sessionRef": "urn:srcos:shell-session:demo-0001",
"commandClass": "turtleterm-open",
"targetRef": "urn:srcos:workspace-op-state:admitted-syncing-demo-0001",
"payload": {
"profileRef": "urn:srcos:shell-profile:default",
"inlineMaterialIncluded": false
},
"isDryRun": false,
"policyDecisionRefs": [
"urn:srcos:policy-decision:op-command-turtleterm-demo-0001"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"stateId": "urn:srcos:workspace-op-state:admitted-syncing-demo-0001",
"specVersion": "0.1.0",
"projectedAt": "2026-05-07T06:00:00Z",
"workspaceRef": "urn:srcos:workspace:professional-intelligence-demo",
"operationState": "admitted",
"fileAvailabilityState": "syncing",
"deviceIdentity": {
"deviceRef": "urn:srcos:device:workstation-demo-0001",
"trustProfile": "workstation-admitted",
"deviceLabel": "dev-workstation-demo"
},
"syncStatus": {
"syncRef": "urn:srcos:syncd-session:demo-0001",
"syncState": "syncing",
"lastSyncedAt": "2026-05-07T05:58:00Z",
"pendingChangeCount": 3
},
"integrationEntryPoints": {
"turtleTerm": {
"commandRef": "urn:srcos:op-command:turtleterm-open-demo-0001",
"available": true,
"sessionRef": "urn:srcos:turtleterm-session:demo-0001"
},
"bearBrowser": {
"commandRef": "urn:srcos:op-command:bearbrowser-open-demo-0001",
"available": true,
"tabRef": null
},
"agentMachine": {
"commandRef": "urn:srcos:op-command:agentmachine-activate-demo-0001",
"available": false,
"agentRegistryRef": null
}
},
"operationTrayProjection": {
"trayEntryRef": "urn:srcos:tray-entry:demo-0001",
"label": "professional-intelligence-demo",
"badgeState": "active"
},
"operationInspectorProjection": {
"inspectorRef": "urn:srcos:inspector:demo-0001",
"detailRefs": [
"urn:srcos:evidence:workspace-op-state-detail-demo-0001"
]
},
"policyDecisionRefs": [
"urn:srcos:policy-decision:workspace-op-state-projection-demo-0001"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
{
"stateId": "urn:srcos:workspace-op-state:conflicted-demo-0001",
"specVersion": "0.1.0",
"projectedAt": "2026-05-07T06:01:00Z",
"workspaceRef": "urn:srcos:workspace:professional-intelligence-demo",
"operationState": "conflicted",
"fileAvailabilityState": "conflicted",
"deviceIdentity": {
"deviceRef": "urn:srcos:device:workstation-demo-0001",
"trustProfile": "user-verified",
"deviceLabel": "dev-workstation-demo"
},
"syncStatus": {
"syncRef": "urn:srcos:syncd-session:demo-0002",
"syncState": "conflict",
"lastSyncedAt": "2026-05-07T05:59:00Z",
"pendingChangeCount": 0
},
"integrationEntryPoints": {
"turtleTerm": {
"commandRef": "urn:srcos:op-command:turtleterm-open-demo-0002",
"available": true,
"sessionRef": null
},
"bearBrowser": {
"commandRef": "urn:srcos:op-command:bearbrowser-open-demo-0002",
"available": true,
"tabRef": null
},
"agentMachine": {
"commandRef": "urn:srcos:op-command:agentmachine-activate-demo-0002",
"available": true,
"agentRegistryRef": "urn:srcos:agent-grant:conflict-resolution-demo"
}
},
"operationTrayProjection": {
"trayEntryRef": "urn:srcos:tray-entry:demo-0002",
"label": "professional-intelligence-demo",
"badgeState": "conflict"
},
"operationInspectorProjection": {
"inspectorRef": "urn:srcos:inspector:demo-0002",
"detailRefs": [
"urn:srcos:evidence:workspace-op-state-conflict-demo-0001"
]
},
"policyDecisionRefs": [
"urn:srcos:policy-decision:workspace-op-state-projection-demo-0002"
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"stateId": "urn:srcos:workspace-op-state:quarantined-demo-0001",
"specVersion": "0.1.0",
"projectedAt": "2026-05-07T06:02:00Z",
"workspaceRef": "urn:srcos:workspace:quarantine-demo",
"operationState": "quarantined",
"fileAvailabilityState": "quarantined",
"deviceIdentity": {
"deviceRef": "urn:srcos:device:workstation-demo-0001",
"trustProfile": "device-only",
"deviceLabel": null
},
"syncStatus": {
"syncRef": "urn:srcos:syncd-session:demo-0003",
"syncState": "offline",
"lastSyncedAt": null,
"pendingChangeCount": null
},
"integrationEntryPoints": {
"turtleTerm": {
"commandRef": "urn:srcos:op-command:turtleterm-open-demo-0003",
"available": false,
"sessionRef": null
},
"bearBrowser": {
"commandRef": "urn:srcos:op-command:bearbrowser-open-demo-0003",
"available": false,
"tabRef": null
},
"agentMachine": {
"commandRef": "urn:srcos:op-command:agentmachine-activate-demo-0003",
"available": false,
"agentRegistryRef": null
}
},
"operationTrayProjection": {
"trayEntryRef": "urn:srcos:tray-entry:demo-0003",
"label": "quarantine-demo",
"badgeState": "quarantined"
},
"operationInspectorProjection": null,
"policyDecisionRefs": [
"urn:srcos:policy-decision:workspace-op-state-quarantine-demo-0001"
]
}
Loading