Add polling sync communication layer

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
wangzhendong
2026-05-15 11:11:18 +08:00
parent 42181b9965
commit b5acead1e1
11 changed files with 481 additions and 6 deletions

3
.gitattributes vendored Normal file
View File

@@ -0,0 +1,3 @@
*.sh text eol=lf
*.ps1 text eol=crlf
*.md text eol=lf

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
.sync-state/
*.log
*.tmp
.DS_Store
Thumbs.db

View File

@@ -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.

View File

@@ -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

51
sync/README.md Normal file
View File

@@ -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.

134
sync/sync-agent.ps1 Normal file
View File

@@ -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)

106
sync/sync-agent.sh Normal file
View File

@@ -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" <<EOF
# VPS Sync Error
- Time: $timestamp
- Repository: $REPO_ROOT
- Message: $message
Manual action required. Do not continue automatic sync until the repository is clean.
EOF
}
has_allowed_changes() {
local line path allowed
while IFS= read -r line; do
[[ -z "$line" ]] && continue
path="${line:3}"
for allowed in "${ALLOWED_PATHS[@]}"; do
if [[ "$path" == "$allowed" || "$path" == "$allowed/"* ]]; then
return 0
fi
done
done < <(git status --porcelain)
return 1
}
has_conflicts() {
[[ -n "$(git diff --name-only --diff-filter=U)" ]]
}
sync_once() {
cd "$REPO_ROOT"
ensure_state_dir
git pull --rebase --autostash
if has_conflicts; then
return 20
fi
if ! has_allowed_changes; then
return 0
fi
local path
for path in "${ALLOWED_PATHS[@]}"; do
if [[ -e "$path" ]]; then
git add -- "$path"
fi
done
if [[ -z "$(git diff --cached --name-only)" ]]; then
return 0
fi
git commit -m "Sync agent state from VPS at $(date '+%Y-%m-%d %H:%M:%S')"
git push
}
while true; do
if sync_once; then
rm -f "$ERROR_FILE"
else
exit_code="$?"
write_sync_error "sync failed with exit code $exit_code"
echo "sync failed with exit code $exit_code" >&2
exit "$exit_code"
fi
if [[ "$ONCE" == "--once" ]]; then
break
fi
sleep "$INTERVAL_SECONDS"
done

44
tasks/README.md Normal file
View File

@@ -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<ID>-short-topic.md
```
Example:
```text
T3-PC-baseline.md
```
## Required Fields
Each task should include:
- Status
- Owner
- Dependencies
- Scope
- Required evidence
- Stop conditions

43
tasks/T3-PC-baseline.md Normal file
View File

@@ -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.

44
tasks/T4-VPS-baseline.md Normal file
View File

@@ -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.

View File

@@ -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.