From b5acead1e13fd9c39fa8cab6e618e2109b788b24 Mon Sep 17 00:00:00 2001 From: wangzhendong Date: Fri, 15 May 2026 11:11:18 +0800 Subject: [PATCH] Add polling sync communication layer Co-authored-by: Cursor --- .gitattributes | 3 + .gitignore | 5 ++ AGENT_BOARD.md | 9 ++- handoff/ORCHESTRATOR.md | 12 ++-- sync/README.md | 51 +++++++++++++ sync/sync-agent.ps1 | 134 +++++++++++++++++++++++++++++++++++ sync/sync-agent.sh | 106 +++++++++++++++++++++++++++ tasks/README.md | 44 ++++++++++++ tasks/T3-PC-baseline.md | 43 +++++++++++ tasks/T4-VPS-baseline.md | 44 ++++++++++++ tasks/T5-verify-baselines.md | 36 ++++++++++ 11 files changed, 481 insertions(+), 6 deletions(-) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 sync/README.md create mode 100644 sync/sync-agent.ps1 create mode 100644 sync/sync-agent.sh create mode 100644 tasks/README.md create mode 100644 tasks/T3-PC-baseline.md create mode 100644 tasks/T4-VPS-baseline.md create mode 100644 tasks/T5-verify-baselines.md diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..589de4d --- /dev/null +++ b/.gitattributes @@ -0,0 +1,3 @@ +*.sh text eol=lf +*.ps1 text eol=crlf +*.md text eol=lf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7805c28 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.sync-state/ +*.log +*.tmp +.DS_Store +Thumbs.db diff --git a/AGENT_BOARD.md b/AGENT_BOARD.md index ae63fc3..0e33a5e 100644 --- a/AGENT_BOARD.md +++ b/AGENT_BOARD.md @@ -17,6 +17,8 @@ Bring the Windows 11 always-on PC, Tencent Cloud VPS OpenClaw Gateway, phone Con - VPS control-plane path: `/home/ubuntu/openclaw-control-plane`. - Secrets policy: no password, token, API key, or `OPENCLAW_GATEWAY_TOKEN` may be written into repo files, handoffs, evidence, or chat. - Frozen website policy: strict freeze during ICP/public-security filing review. Agents must not change the `smartmotor.cloud` homepage, content reachable from homepage links, static assets, Nginx routing, bind mounts, container images, or `/opt/services/docker-composite.yml` entries that could alter public website output. +- Communication MVP: use Git-backed polling sync scripts under `sync/` plus task files under `tasks/`. This reduces manual pull/push but is not the final async-notification design. +- Future communication target: when the baseline path is stable, design an event-driven coordinator using Gitea webhooks, Gitea Issues, OpenClaw events, or Cursor SDK agent orchestration. ## Agent Roles @@ -47,8 +49,9 @@ Bring the Windows 11 always-on PC, Tencent Cloud VPS OpenClaw Gateway, phone Con | T0 | Create local control-plane scaffold | ORCHESTRATOR | None | Done | | T1 | Create standalone Gitea repo for this control plane | User + ORCHESTRATOR | T0 | Done | | T2 | Sync this scaffold to Gitea and open on PC/VPS Cursor | ORCHESTRATOR + VPS_EXECUTOR | T1 | Done | -| T3 | Run read-only PC baseline discovery | PC_EXECUTOR | T2 | Ready | -| T4 | Run read-only VPS baseline discovery | VPS_EXECUTOR | T2 | Ready | +| T2.1 | Add polling sync and task-file communication MVP | ORCHESTRATOR | T2 | In Progress | +| T3 | Run read-only PC baseline discovery | PC_EXECUTOR | T2.1 | Ready | +| T4 | Run read-only VPS baseline discovery | VPS_EXECUTOR | T2.1 | Ready | | T5 | Verify both baselines before any config change | PC_VERIFIER + VPS_VERIFIER | T3, T4 | Pending | ## Acceptance Criteria Draft @@ -67,5 +70,7 @@ Bring the Windows 11 always-on PC, Tencent Cloud VPS OpenClaw Gateway, phone Con - Executors must not accept work outside their named scope. - Executors must not validate their own work as complete. - VPS-related agents must treat the `smartmotor.cloud` website defined by `/opt/services/docker-composite.yml` as frozen: no edits to homepage content, linked page content, routing, static assets, bind mounts, container images, or Nginx rules that could alter what public visitors see. +- Polling sync scripts are convenience automation only. If they report conflict, authentication failure, or unexpected files, stop and let CORRECTION review. +- Task files under `tasks/` are the agent-to-agent work contract. Chat messages are not the source of truth. - Any system-level change requires a rollback note before execution. - Any blocking issue must be recorded in the relevant handoff file and surfaced to ORCHESTRATOR. diff --git a/handoff/ORCHESTRATOR.md b/handoff/ORCHESTRATOR.md index 7143bf1..109052d 100644 --- a/handoff/ORCHESTRATOR.md +++ b/handoff/ORCHESTRATOR.md @@ -22,18 +22,22 @@ Bootstrap the shared Gitea-backed control plane, then coordinate read-only basel - Access mode: HTTPS. - Default branch: `main`. - Strict `smartmotor.cloud` website freeze is a hard requirement during filing review. +- Communication MVP uses polling Git sync scripts in `sync/` and task files in `tasks/`. +- The polling sync is intentionally temporary; design an async notification/coordinator layer when PC/VPS baseline work is stable. ## Next Actions -1. Commit and push this path correction to Gitea. -2. Run G0 requirements and acceptance review with the user. -3. Assign PC and VPS read-only baseline tasks in their respective Cursor windows. -4. Require verifier review before any mutation. +1. Commit and push the communication MVP files to Gitea. +2. Ask the user to start or approve starting one sync script on PC and one on VPS. +3. Run G0 requirements and acceptance review with the user. +4. Assign PC and VPS read-only baseline tasks in their respective Cursor windows. +5. Require verifier review before any mutation. ## Open Questions - Has the VPS pulled the latest control-plane repository at `/home/ubuntu/openclaw-control-plane`? - Should Gitea Issues be used immediately for task tracking, or should `AGENT_BOARD.md` remain the first source of truth for the initial run? +- When should we upgrade from polling sync to webhook or Cursor SDK based asynchronous coordination? ## Last Update diff --git a/sync/README.md b/sync/README.md new file mode 100644 index 0000000..fd1b3dd --- /dev/null +++ b/sync/README.md @@ -0,0 +1,51 @@ +# Sync Layer + +This is the MVP communication layer for PC and VPS agents. + +It uses polling-based Git synchronization. Git is the durable source of truth and audit log, while these scripts reduce manual `pull` and `push` work. + +## PC + +Run from `D:\openclaw-control-plane`: + +```powershell +.\sync\sync-agent.ps1 +``` + +Run one cycle only: + +```powershell +.\sync\sync-agent.ps1 -Once +``` + +## VPS + +Run from `/home/ubuntu/openclaw-control-plane`: + +```bash +bash sync/sync-agent.sh +``` + +Run one cycle only: + +```bash +bash sync/sync-agent.sh --once +``` + +## Rules + +- Scripts only stage known control-plane paths. +- Agents should avoid editing the same file concurrently. +- `AGENT_BOARD.md` is owned by ORCHESTRATOR. +- Each role owns its own `handoff/*.md` file. +- Evidence files should be append-only by unique filename. +- On conflict or sync failure, stop the script and resolve manually. + +## Future Upgrade + +This polling layer should be replaced or supplemented when conditions are mature: + +- Gitea webhook triggers for pull notifications. +- Gitea Issues as the task queue. +- OpenClaw Gateway events for cross-device command triggers. +- Cursor SDK based coordinator for creating, resuming, and supervising agents. diff --git a/sync/sync-agent.ps1 b/sync/sync-agent.ps1 new file mode 100644 index 0000000..5299dd0 --- /dev/null +++ b/sync/sync-agent.ps1 @@ -0,0 +1,134 @@ +param( + [int]$IntervalSeconds = 30, + [switch]$Once +) + +$ErrorActionPreference = "Stop" + +$RepoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..")).Path +$StateDir = Join-Path $RepoRoot ".sync-state" +$ErrorFile = Join-Path $StateDir "sync-error-pc.md" +$AllowedPaths = @( + "AGENT_BOARD.md", + "README.md", + ".cursor/rules", + "handoff", + "evidence", + "rollback", + "tasks", + "sync", + ".gitignore" +) + +function Ensure-StateDir { + if (-not (Test-Path $StateDir)) { + New-Item -ItemType Directory -Path $StateDir | Out-Null + } +} + +function Write-SyncError { + param([string]$Message) + + Ensure-StateDir + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss zzz" + @" +# PC Sync Error + +- Time: $timestamp +- Repository: $RepoRoot +- Message: $Message + +Manual action required. Do not continue automatic sync until the repository is clean. +"@ | Set-Content -Path $ErrorFile -Encoding UTF8 +} + +function Invoke-Git { + param([string[]]$GitArgs) + & git @GitArgs + if ($LASTEXITCODE -ne 0) { + throw "git $($GitArgs -join ' ') failed with exit code $LASTEXITCODE" + } +} + +function Get-AllowedChanges { + $changes = & git -C $RepoRoot status --porcelain + if ($LASTEXITCODE -ne 0) { + throw "git status failed with exit code $LASTEXITCODE" + } + + return $changes | Where-Object { + $line = $_ + if ([string]::IsNullOrWhiteSpace($line)) { + return $false + } + $path = $line.Substring(3).Trim() + foreach ($allowed in $AllowedPaths) { + if ($path -eq $allowed -or $path.StartsWith("$allowed/") -or $path.StartsWith("$allowed\")) { + return $true + } + } + return $false + } +} + +function Test-ConflictMarkers { + $conflicts = & git -C $RepoRoot diff --name-only --diff-filter=U + if ($LASTEXITCODE -ne 0) { + throw "git diff conflict check failed with exit code $LASTEXITCODE" + } + return -not [string]::IsNullOrWhiteSpace(($conflicts -join "")) +} + +function Sync-Once { + Set-Location $RepoRoot + Ensure-StateDir + + Invoke-Git @("pull", "--rebase", "--autostash") + + if (Test-ConflictMarkers) { + throw "merge or rebase conflicts detected" + } + + $allowedChanges = @(Get-AllowedChanges) + if ($allowedChanges.Count -eq 0) { + return + } + + foreach ($path in $AllowedPaths) { + if (Test-Path (Join-Path $RepoRoot $path)) { + Invoke-Git @("add", "--", $path) + } + } + + $staged = & git -C $RepoRoot diff --cached --name-only + if ($LASTEXITCODE -ne 0) { + throw "git diff --cached failed with exit code $LASTEXITCODE" + } + if ([string]::IsNullOrWhiteSpace(($staged -join ""))) { + return + } + + $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" + Invoke-Git @("commit", "-m", "Sync agent state from PC at $timestamp") + Invoke-Git @("push") +} + +do { + try { + Sync-Once + if (Test-Path $ErrorFile) { + Remove-Item $ErrorFile -Force + } + } + catch { + Write-SyncError $_.Exception.Message + Write-Error $_ + break + } + + if ($Once) { + break + } + + Start-Sleep -Seconds $IntervalSeconds +} while ($true) diff --git a/sync/sync-agent.sh b/sync/sync-agent.sh new file mode 100644 index 0000000..ea36d34 --- /dev/null +++ b/sync/sync-agent.sh @@ -0,0 +1,106 @@ +#!/usr/bin/env bash +set -euo pipefail + +INTERVAL_SECONDS="${INTERVAL_SECONDS:-30}" +ONCE="${1:-}" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +STATE_DIR="$REPO_ROOT/.sync-state" +ERROR_FILE="$STATE_DIR/sync-error-vps.md" + +ALLOWED_PATHS=( + "AGENT_BOARD.md" + "README.md" + ".cursor/rules" + "handoff" + "evidence" + "rollback" + "tasks" + "sync" + ".gitignore" +) + +ensure_state_dir() { + mkdir -p "$STATE_DIR" +} + +write_sync_error() { + ensure_state_dir + local message="$1" + local timestamp + timestamp="$(date '+%Y-%m-%d %H:%M:%S %z')" + cat > "$ERROR_FILE" <&2 + exit "$exit_code" + fi + + if [[ "$ONCE" == "--once" ]]; then + break + fi + + sleep "$INTERVAL_SECONDS" +done diff --git a/tasks/README.md b/tasks/README.md new file mode 100644 index 0000000..4410bb8 --- /dev/null +++ b/tasks/README.md @@ -0,0 +1,44 @@ +# Tasks + +Tasks are the handoff contract between agents. They are not a real-time queue; sync scripts move them between PC and VPS through Git. + +## Status Values + +- `draft`: Created but not ready to claim. +- `ready`: Ready for the assigned role. +- `claimed`: Agent has started the task. +- `blocked`: Agent cannot proceed and wrote the blocker. +- `done`: Executor has completed the task and produced evidence. +- `accepted`: Verifier or ORCHESTRATOR accepted the task. + +## Ownership + +- ORCHESTRATOR creates and updates task intent. +- Executors update only tasks assigned to their role. +- Verifiers update verification tasks and may mark executor tasks accepted after review. +- CORRECTION may mark a task blocked if it detects drift or unsafe execution. + +## File Naming + +Use: + +```text +T-short-topic.md +``` + +Example: + +```text +T3-PC-baseline.md +``` + +## Required Fields + +Each task should include: + +- Status +- Owner +- Dependencies +- Scope +- Required evidence +- Stop conditions diff --git a/tasks/T3-PC-baseline.md b/tasks/T3-PC-baseline.md new file mode 100644 index 0000000..0defe49 --- /dev/null +++ b/tasks/T3-PC-baseline.md @@ -0,0 +1,43 @@ +# T3 - PC Baseline Discovery + +## Status + +ready + +## Owner + +PC_EXECUTOR + +## Dependencies + +- T2 sync scaffold available on PC and VPS +- G0 requirement review may still be pending; this task is read-only only + +## Scope + +Collect current Windows PC baseline evidence for OpenClaw execution-node readiness. + +## Allowed Actions + +- Read local state. +- Run harmless diagnostic commands. +- Write evidence to `evidence/pc-baseline-YYYYMMDD.md`. +- Update `handoff/PC_EXECUTOR.md`. + +## Required Evidence + +- `openclaw --version` +- `openclaw node --help` +- Tailscale executable path and login/status summary +- `Test-NetConnection openclaw.smartmotor.cloud -Port 443` +- Confirmation that no PC service port was exposed publicly + +## Stop Conditions + +- Any command requests or prints a secret. +- Any step requires modifying PC services, scheduled tasks, firewall rules, or environment variables. +- Evidence contradicts `OPENCLAW_EXEC_NODE_PLAN.md` and needs ORCHESTRATOR review. + +## Acceptance + +PC_VERIFIER must review the evidence before this task is accepted. diff --git a/tasks/T4-VPS-baseline.md b/tasks/T4-VPS-baseline.md new file mode 100644 index 0000000..017af1b --- /dev/null +++ b/tasks/T4-VPS-baseline.md @@ -0,0 +1,44 @@ +# T4 - VPS Baseline Discovery + +## Status + +ready + +## Owner + +VPS_EXECUTOR + +## Dependencies + +- T2 sync scaffold available on PC and VPS +- G0 requirement review may still be pending; this task is read-only only + +## Scope + +Collect current VPS baseline evidence for OpenClaw Gateway, Gitea, Docker stack, and approval-command readiness. + +## Allowed Actions + +- Read VPS service state. +- Run harmless diagnostic commands. +- Write evidence to `evidence/vps-baseline-YYYYMMDD.md`. +- Update `handoff/VPS_EXECUTOR.md`. + +## Required Evidence + +- Control-plane repo status at `/home/ubuntu/openclaw-control-plane` +- OpenClaw Gateway process or container status +- High-level Docker stack status for Gateway, Nginx, Gitea, Confluence, and Postgres +- Nginx route summary for OpenClaw without changing routing +- Availability of `openclaw devices approve`, `openclaw nodes pending`, and `openclaw nodes approve` or their current CLI equivalents +- Confirmation that the frozen `smartmotor.cloud` website was not modified + +## Stop Conditions + +- Any command requests or prints a secret. +- Any step would modify `/opt/services/docker-composite.yml`, public website files, Nginx routes, Docker bind mounts, container images, or service state. +- Any restart, reload, approval, token rotation, or Gateway configuration change is required. + +## Acceptance + +VPS_VERIFIER must review the evidence before this task is accepted. diff --git a/tasks/T5-verify-baselines.md b/tasks/T5-verify-baselines.md new file mode 100644 index 0000000..6b182fe --- /dev/null +++ b/tasks/T5-verify-baselines.md @@ -0,0 +1,36 @@ +# T5 - Verify PC and VPS Baselines + +## Status + +draft + +## Owner + +PC_VERIFIER and VPS_VERIFIER + +## Dependencies + +- T3 done +- T4 done + +## Scope + +Independently verify PC and VPS baseline evidence before any configuration mutation. + +## Required Evidence + +- PC baseline evidence reviewed and accepted or returned with findings +- VPS baseline evidence reviewed and accepted or returned with findings +- Confirmation that no executor accepted its own work +- Confirmation that frozen website policy remains intact + +## Stop Conditions + +- Missing evidence. +- Evidence includes secrets. +- Evidence shows drift from the mission or from `OPENCLAW_EXEC_NODE_PLAN.md`. +- Evidence suggests a required mutation before G0 has been completed. + +## Acceptance + +ORCHESTRATOR may move G1 to accepted only after both verifier roles record acceptance.