Add polling sync communication layer
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
3
.gitattributes
vendored
Normal file
3
.gitattributes
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
*.sh text eol=lf
|
||||
*.ps1 text eol=crlf
|
||||
*.md text eol=lf
|
||||
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
.sync-state/
|
||||
*.log
|
||||
*.tmp
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
@@ -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.
|
||||
|
||||
@@ -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
51
sync/README.md
Normal 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
134
sync/sync-agent.ps1
Normal 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
106
sync/sync-agent.sh
Normal 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
44
tasks/README.md
Normal 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
43
tasks/T3-PC-baseline.md
Normal 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
44
tasks/T4-VPS-baseline.md
Normal 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.
|
||||
36
tasks/T5-verify-baselines.md
Normal file
36
tasks/T5-verify-baselines.md
Normal 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.
|
||||
Reference in New Issue
Block a user