# Send Safe Update/Merge Skill to your agent
Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.
## Fast path
- Download the package from Yavira.
- Extract it into a folder your agent can access.
- Paste one of the prompts below and point your agent at the extracted folder.
## Suggested prompts
### New install

```text
I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete.
```
### Upgrade existing

```text
I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run.
```
## Machine-readable fields
```json
{
  "schemaVersion": "1.0",
  "item": {
    "slug": "safe-update-merge",
    "name": "Safe Update/Merge Skill",
    "source": "tencent",
    "type": "skill",
    "category": "效率提升",
    "sourceUrl": "https://clawhub.ai/maverick-software/safe-update-merge",
    "canonicalUrl": "https://clawhub.ai/maverick-software/safe-update-merge",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadUrl": "/downloads/safe-update-merge",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=safe-update-merge",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "packageFormat": "ZIP package",
    "primaryDoc": "SKILL.md",
    "includedAssets": [
      "MERGE_MANIFEST.json",
      "SKILL.md",
      "references/app-state-patch.ts",
      "references/bg-sessions-backend.ts",
      "references/bg-sessions-controller.ts",
      "references/bg-sessions-views.ts"
    ],
    "downloadMode": "redirect",
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-30T16:55:25.780Z",
      "expiresAt": "2026-05-07T16:55:25.780Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=network",
        "contentDisposition": "attachment; filename=\"network-1.0.0.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/safe-update-merge"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    }
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/safe-update-merge",
    "downloadUrl": "https://openagent3.xyz/downloads/safe-update-merge",
    "agentUrl": "https://openagent3.xyz/skills/safe-update-merge/agent",
    "manifestUrl": "https://openagent3.xyz/skills/safe-update-merge/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/safe-update-merge/agent.md"
  }
}
```
## Documentation

### Safe Merge Update

Merges upstream OpenClaw changes into your fork while preserving all custom code:
plugin registrations, custom UI tabs, workspace skills, controllers, and state extensions.

### ⚠️ Operator Warnings — Read Before Running

This skill performs high-impact, partially irreversible operations. Understand what it does before executing in a production environment:

OperationPhaseImpactgit merge upstream/mainPhase 1Creates safe-merge-YYYY-MM-DD branch and merges — no changes to local-desktop-mainnpm run build / pnpm run buildPhase 1Downloads packages if lockfile changed (network); builds in placesystemctl --user restart openclaw-gatewayPhase 1Restarts the live gateway — brief downtime; gateway now runs from safe-merge buildConflict resolution via claude CLIPhase 1 (optional)Passes redacted file content to the Claude API; Edit+Read tools only — Bash explicitly excludedgit push --force to TARGET_REMOTE/TARGET_BRANCHPhase 2 only (--promote)Overwrites remote branch — only runs after user confirms gateway is healthygit branch -D safe-merge-*Phase 2 only (--promote)Deletes temp branch after successful promotion

### Prerequisites

Before running, verify:

git remote -v shows upstream pointing to github.com/openclaw/openclaw (or set UPSTREAM_REMOTE)
git remote -v shows myfork pointing to your fork (or set TARGET_REMOTE)
Branch local-desktop-main exists locally (or set TARGET_BRANCH)
claude CLI is installed and authenticated (claude --version)
npm or pnpm is available for builds
You are OK with the gateway restarting automatically on success

### Conflict Resolution & Secret Redaction

When merge conflicts occur, the script:

Runs scripts/redact-secrets.sh on each conflicted file — replaces secrets with [REDACTED_N] placeholders, writes the redaction map to a per-file temp file in a mode-700 directory
Invokes the claude CLI with --allowedTools Edit,Read (no Bash) to resolve conflict markers in the redacted files — the model cannot execute shell commands
After claude exits, the script runs git add -A && git commit --no-edit itself
Restores secrets from the redaction map, then deletes the map files immediately

If you prefer manual resolution, skip claude entirely: fix conflicts yourself and run --resume.

### Flags

FlagDescription--dry-runFetch remotes, show divergence and estimated conflict count, then exit — no changes made--no-auto-resolveStop on conflicts instead of invoking claude — leaves the safe-merge branch for manual resolution, then use --resume--resume <branch>Skip the merge; run build → restart on an existing safe-merge branch (use after manual conflict resolution)--promote <branch>Phase 2 — run after user confirms the gateway is healthy. Force-pushes the safe-merge branch to TARGET_REMOTE/TARGET_BRANCH, switches local branch, deletes temp branch. This is the only step that modifies local-desktop-main.

### All Environment Variables

VariableDefaultDescriptionREPO_DIR(required)Path to your OpenClaw repositoryUPSTREAM_REMOTEupstreamRemote name for openclaw/openclawUPSTREAM_BRANCHmainBranch to pull from upstreamTARGET_REMOTEmyforkRemote to force-push result toTARGET_BRANCHlocal-desktop-mainBranch to promote on successLOCAL_BRANCHcurrent branchThe branch being merged from (used by preflight.sh for divergence stats)PACKAGE_MGRauto-detectnpm or pnpm (auto-detected from lockfile)

### How It Works

Pre-flight: Fetch upstream, compute divergence, detect conflicts
AI Merge: The agent resolves each conflict using the merge manifest as intent context
Validate: Build check, tab verification, protected pattern scan
Report: Announce results back to the requesting session

### Model Usage

This skill uses the claude CLI (the Anthropic Claude Code CLI, not the OpenClaw agent model) for conflict resolution. The CLI must be installed separately and authenticated with an Anthropic API key in your environment. It is invoked with --allowedTools Edit,Read — the Bash tool is explicitly excluded, so the model can only read and edit files, not execute shell commands.

The model sees only the redacted content of conflicted files (see Secret Redaction below) — not the entire repository.

To control which Claude model is used, configure it in your ~/.claude/config.json or set the model via claude CLI flags.

### Secret Redaction

Before any file content is sent to the claude CLI for conflict resolution, it passes through scripts/redact-secrets.sh which detects and replaces:

API keys (OpenAI sk-, GitHub ghp_, Slack xoxb-, AWS AKIA, etc.)
Bearer/Basic auth tokens
Private keys (RSA, EC, OPENSSH)
Connection strings with embedded passwords
Config values for password, secret, token, apiKey fields

Detected secrets are replaced with [REDACTED_N] placeholders.

How the map is stored: redact-secrets.sh requires fd 3 to be open and writes the redaction map to whatever file fd 3 points to. In safe-merge-update.sh, fd 3 is wired to a per-file temp file inside a mode-700 temp directory (mktemp -d). So the map is written to disk — in a private, process-owned temp directory — and deleted immediately after secret restoration. It is never written to stdout, stderr, or any shared/world-readable path.

If your security policy requires no disk writes, mount the temp dir on a tmpfs:

REDACT_MAP_DIR=$(mktemp -d)
mount -t tmpfs -o size=1m,mode=700 tmpfs "$REDACT_MAP_DIR"
# ... run safe-merge-update.sh with REDACT_MAP_DIR set ...
umount "$REDACT_MAP_DIR" && rmdir "$REDACT_MAP_DIR"

What is sent to the claude CLI: Only the redacted content of conflicted files. Claude resolves conflict markers (<<<<<<<, =======, >>>>>>>) using only the Edit and Read tools — Bash is not granted, so the model cannot execute shell commands. The script itself runs git add -A && git commit --no-edit after claude finishes.

Backups in /tmp/safe-merge/backups/ contain only redacted content — they are created after redaction and never contain plaintext secrets.

### What Gets Sent to the Model

Only conflicting file diffs are sent (not the entire repository)
All secrets are redacted before transmission (see above)
The merge manifest describes file intents and protected patterns
.env files are never included in merge prompts

### Build Execution

The validation phase runs pnpm install --ignore-scripts, pnpm build, and pnpm ui:build to verify the merge compiles.

pnpm install will download packages from the npm registry. This is network activity. --ignore-scripts is always passed to suppress preinstall/postinstall lifecycle hooks from running untrusted code.

Before proceeding past pre-flight:

Review upstream package.json diffs in the pre-flight report
Check for new dependencies you don't recognize before running install
For maximum safety, run the full merge in an isolated environment (container, VM, or disposable clone)

SKILL.md says "No Network Installs" — this refers to the skill package itself (no curl/wget/npm install in the skill's own setup). It does NOT mean the merge workflow avoids network; git fetch upstream and pnpm install both require network access.

### Backups (Non-Negotiable)

Before ANY file edits, the skill creates a full backup of every conflicting file at /tmp/safe-merge/backups/ preserving directory structure. Backups are created after secret redaction — they never contain plaintext secrets. If the merge goes wrong, restore from backups and re-run secret restoration.

### No Network Installs

This skill contains no install scripts that download from external URLs. All files are local to the skill package. The only network activity is git fetch upstream and your normal model API calls.

### Via UI

Click the ↑ Update button in the topbar (right of Health pill).

### Via Chat

/update — or ask: "run a safe merge update"

### Fully Automated Pipeline (scripts/safe-merge-update.sh)

The primary entry point. Run this directly — it handles the entire workflow end-to-end:

cd /path/to/openclaw

# Safe first step — shows divergence, makes no changes
REPO_DIR=. ./scripts/safe-merge-update.sh --dry-run

# Phase 1 — merge, build, restart gateway from safe-merge branch
# local-desktop-main is NOT touched; no remote push yet
REPO_DIR=. ./scripts/safe-merge-update.sh

# Manual mode — stop on conflicts for review instead of invoking claude
REPO_DIR=. ./scripts/safe-merge-update.sh --no-auto-resolve

# Resume after fixing conflicts manually (still Phase 1)
REPO_DIR=. ./scripts/safe-merge-update.sh --resume safe-merge-2026-03-02

# Phase 2 — after verifying the gateway is healthy, promote to local-desktop-main
REPO_DIR=. ./scripts/safe-merge-update.sh --promote safe-merge-2026-03-02

Two-phase design — local-desktop-main is never touched until the user confirms:

Phase 1 (automated):

Checks you're on local-desktop-main with a clean working tree
--dry-run: fetches, shows upstream divergence + estimated conflict count, exits — no changes
git fetch --all
Prunes any stale safe-merge-* branches (prevents accumulation)
Creates safe-merge-YYYY-MM-DD branch
Runs git merge upstream/main --no-edit
If conflicts → redacts secrets (maps written to mode-700 temp dir via fd 3, deleted after restore), invokes claude --allowedTools Edit,Read (Bash excluded), restores secrets, runs git commit — use --no-auto-resolve to stop for manual review
pnpm build + pnpm ui:build
Restarts gateway from current working tree (safe-merge branch build)
Exits with confirmation prompt — local-desktop-main is unchanged, no remote push yet
On build failure: leaves safe-merge branch intact for investigation

Phase 2 (user-confirmed via --promote):

User verifies gateway is healthy
git push myfork safe-merge-YYYY-MM-DD:local-desktop-main --force
git checkout local-desktop-main && git reset --hard safe-merge-YYYY-MM-DD
git branch -D safe-merge-YYYY-MM-DD

Rollback before confirming: gateway restart reverts to previous build; local-desktop-main was never touched.

Claude conflict resolution strategy (baked into the script):

local-desktop-main UI/vault/navigation customizations → prefer HEAD (ours)
Upstream security and bug fixes → prefer incoming (theirs)
Additive changes on both sides → keep both
TypeScript type unions → union both sides
Genuinely ambiguous → prefer HEAD

Resume mode — for cases where Claude's auto-resolution needs a manual touch:

# Fix conflicts manually, then:
./scripts/safe-merge-update.sh --resume safe-merge-2026-03-02
# Skips merge, runs build → push → cleanup

### Supporting Scripts (for advanced / manual use)

scripts/preflight.sh — read-only analysis, produces JSON report at /tmp/safe-merge/preflight-report.json
scripts/validate.sh — post-merge build + mustPreserve pattern checks
scripts/merge-agent-prompt.md — prompt template for per-file conflict resolution (used when invoking Claude manually)
scripts/redact-secrets.sh — secret detection and redaction before model transmission

### Branch Strategy

Working branch: local-desktop-main (your fork's primary branch)
Temp merge branch: safe-merge-YYYY-MM-DD (created and destroyed per run)
Upstream source: upstream/main (openclaw/openclaw official repo)
Push target: myfork/local-desktop-main
Stale safe-merge branches are auto-pruned at the start of each run — no accumulation

### Phase 1: Pre-flight (scripts/preflight.sh)

Run automatically when invoked. Produces a report at /tmp/safe-merge/preflight-report.json.

What it does:

Fetches upstream (git fetch upstream)
Computes commit divergence (ahead/behind counts)
Lists conflicting files via git merge-tree
Checks each conflict against the merge manifest for protection status
Creates a temporary worktree for dry-run merge (avoids touching your working tree)

Pre-flight report includes:

Divergence stats
List of conflicting files with protection status
Recommended strategy per file (keep-ours, ai-merge, accept-upstream)

Environment variables:

REPO_DIR — Path to your OpenClaw repo (must be set explicitly)
UPSTREAM_REMOTE — Upstream remote name (default: upstream)
UPSTREAM_BRANCH — Upstream branch (default: main)

### Phase 2: Merge & Conflict Resolution

The agent performs the actual merge and resolves conflicts:

Create merge branch — git checkout -b safe-merge-YYYY-MM-DD
Examine conflicts before merging — read both our version and upstream's version of each conflicting file to understand what each side changed
Run the merge — git merge upstream/main --no-commit --no-ff
For each conflicting file:
a. Read the conflict markers to understand the exact diff
b. Check MERGE_MANIFEST.json for intent and strategy (keep-ours, accept-upstream, ai-merge)
c. Resolve: write the clean merged file preserving our customizations + upstream improvements
d. git add the resolved file
Verify auto-merged protected files — even files that auto-merge need checking: grep for mustPreserve patterns to confirm our custom code survived
Secret redaction (for complex conflicts requiring prompt-based resolution):

scripts/redact-secrets.sh replaces secrets with [REDACTED_N] placeholders
Redaction map is written to a per-file temp file in a mode-700 directory via fd 3; it is never written to stdout, stderr, or any shared path, and is deleted immediately after secret restoration
After resolution, restore secrets from map, then delete the temp directory

Key principle: Always examine both sides of a conflict BEFORE attempting resolution. Understanding what upstream changed and what we customized is essential for correct merges.

### Phase 3: Validation (scripts/validate.sh)

After all conflicts are resolved:

pnpm install --ignore-scripts — install any new dependencies (lifecycle scripts suppressed)
pnpm build — compile the gateway
pnpm ui:build — compile the Control UI
Protected pattern scan — verify mustPreserve patterns from the manifest still exist
Tab verification — check that custom UI tabs are still registered

### Phase 4: Commit & Report

Commits on the merge branch (safe-merge-YYYY-MM-DD) — never directly on main
Commit message includes: upstream version, commit count, conflict resolution summary, file counts
Reports to user: files resolved, strategies used, build status, any warnings
User decides whether to merge the branch into main and push:
git checkout main
git merge safe-merge-YYYY-MM-DD
git push origin main

### Configuration

VariableDefaultDescriptionREPO_DIR(required, declared in metadata)Path to your OpenClaw repositorySAFE_MERGE_MODEL(agent's current model)Model override for conflict resolutionUPSTREAM_REMOTEupstreamGit remote name for upstreamUPSTREAM_BRANCHmainUpstream branch to merge from

### Merge Model Selection

The model used for AI conflict resolution can be configured in two ways:

Via the UI modal — The update modal includes a "Merge Model" dropdown that lists all available models (same catalog as Agents → Model Selection). The selection is persisted in localStorage under the key openclaw-merge-model and survives page reloads. When a model is selected and "Run Safe Merge" is clicked, the merge prompt includes SAFE_MERGE_MODEL=<selected-model>.


Via environment variable — Set SAFE_MERGE_MODEL before invoking the skill (e.g., in the agent's env config or inline).

If neither is set, the skill uses the agent's currently configured primary model.

The dropdown appears on both the initial "Check for Updates" screen and the results screen, so you can change it at any point before starting the merge.

### Files

FilePurposeSKILL.mdThis file — skill instructionsMERGE_MANIFEST.jsonProtected files, intents, mustPreserve patternsscripts/preflight.shPre-flight analysis (read-only, no modifications)scripts/validate.shPost-merge build and pattern validationscripts/merge-agent-prompt.mdPrompt template for per-file conflict resolutionscripts/redact-secrets.shSecret detection and redaction before model transmissionupdate-modal.tsReference copy of the UI update modal component (source of truth: ui/src/ui/views/update-modal.ts)references/bg-sessions-backend.tsReference: src/gateway/server-methods/bg-sessions.tsreferences/bg-sessions-controller.tsReference: ui/src/ui/controllers/bg-sessions.tsreferences/bg-sessions-views.tsReference: ui/src/ui/views/bg-sessions.ts

### Background Sessions Panel

A right-side drawer panel that lets you watch and talk to background/cron subagents in real-time, without leaving the Control UI.

### How to Open

Click the updates badge (e.g. "148 Updates") in the status bar — opens the update modal and slides in the background sessions panel simultaneously
Can also be opened programmatically: openBgSessionsPanel(client, state)

### What It Shows

Session list dropdown — all isolated/cron sessions, with 🟢 running / ⚪ idle indicator and a human-readable label extracted from the cron job name
Live transcript — scrollable, role-colored messages:

🟣 You (user injections)
🟢 Agent (assistant responses)
🟡 → tool (tool calls with args)
⚪ ← result (tool results, truncated)
🔴 system (compaction events)


Auto-refresh — polls bgSessions.history every 3 seconds while panel is open
Send messages — text area at the bottom; Enter sends, Shift+Enter newlines. Routes through chat.send RPC using the selected sessionKey

### Architecture

Backend (src/gateway/server-methods/bg-sessions.ts):

bgSessions.list — reads sessions.json for the default agent, filters for isolated/cron session keys (UUID format: agent:main:<uuid>), returns label, updatedAt, running status (lock file presence)
bgSessions.history — loads the .jsonl transcript file via readSessionMessages(), simplifies to { role, text, timestamp, toolName } array
bgSessions.send is intentionally omitted — the UI calls chat.send directly with the target sessionKey

Controller (ui/src/ui/controllers/bg-sessions.ts):

openBgSessionsPanel(client, state) — sets panel open, fetches sessions, starts 3s poll
closeBgSessionsPanel(state) — clears panel open flag, stops poll
loadBgSessions(client, state) — fetches session list via RPC
loadBgSessionHistory(client, state, key) — fetches transcript via RPC
selectBgSession(client, state, key) — changes selected session, reloads history
sendBgMessage(client, state) — calls chat.send RPC with session key + message, refreshes history
startBgSessionsPolling(client, state) / stopBgSessionsPolling() — manage setInterval

View (ui/src/ui/views/bg-sessions.ts):

renderBgSessionsPanel(state, client) — full Lit HTML panel, rendered as overlay in app-render.ts
bgSessionsPanelStyles — exported CSS (for reference; styles are embedded in the view's html template)
Panel is an overlay div (fixed inset-0, z-index 9000) with a right-anchored 520px panel; click outside to close

State fields (added to AppViewState and OpenClawApp):

bgSessionsPanelOpen: boolean;
bgSessionsList: BgSession[] | null;
bgSessionsLoading: boolean;
bgSessionsSelectedKey: string | null;
bgSessionsHistory: BgMessage[] | null;
bgSessionsHistoryLoading: boolean;
bgSessionsInput: string;
bgSessionsSending: boolean;

### Wiring in app-render.ts

The panel is rendered as the last overlay before the closing </div>:

${state.bgSessionsPanelOpen && state.client ? renderBgSessionsPanel(state, state.client) : nothing}

The update badge click handler also calls openBgSessionsPanel:

@click=${() => {
  // ...existing update modal logic...
  if ((state as any).client) { openBgSessionsPanel((state as any).client, state as any); }
}}

### MERGE_MANIFEST.json — Add These Entries

When merging future upstream changes, protect these new files:

"src/gateway/server-methods/bg-sessions.ts": {
  "intent": "New RPC handlers for background session listing and history (bgSessions.list, bgSessions.history)",
  "strategy": "keep-ours"
},
"ui/src/ui/controllers/bg-sessions.ts": {
  "intent": "Controller for the background sessions panel — load, poll, send, select",
  "strategy": "keep-ours"
},
"ui/src/ui/views/bg-sessions.ts": {
  "intent": "Right-side drawer panel for viewing/talking to cron subagents",
  "strategy": "keep-ours"
}

Also add these mustPreserve patterns to the relevant existing protected files:

ui/src/ui/app-render.ts: renderBgSessionsPanel, openBgSessionsPanel, bgSessionsPanelOpen
ui/src/ui/app.ts: bgSessionsPanelOpen, bgSessionsList, bgSessionsSelectedKey
ui/src/ui/app-view-state.ts: bgSessionsPanelOpen, bgSessionsList

### UI Update Modal

Clicking the topbar update button (in any state) opens an update modal with a guided flow:

Check for Updates — asks the user to confirm, then calls update.checkUpstream RPC with force: true (bypasses cache)
Status Result — shows upstream divergence: commits behind, commits ahead, or "Up to date"
Action Buttons — "⚡ Run Safe Merge" (if behind) or "🔄 Run Merge Anyway" (if up to date) — both send the merge prompt to the chat session

The modal is rendered by ui/src/ui/views/update-modal.ts and uses state properties updateModalState (closed/confirm/checking/result), upstreamDivergence, and mergeModel on the app component. A reference copy of the modal source is kept at skills/safe-merge-update/update-modal.ts.

### Button States

N Updates (accent-colored): Git upstream has N newer commits
Updates Available (accent-colored): npm registry has a newer version (non-fork workflows)
✓ Up to Date (muted pill, clickable): Up to date — click still opens the modal to re-check
Merging… (spinner, disabled): Merge in progress

### How Update Detection Works

The gateway runs two parallel checks:

npm registry (update-startup.ts): Compares VERSION against npm latest. Used for standard installs.
Git upstream (update.checkUpstream RPC): Runs git fetch upstream && git rev-list --count HEAD..upstream/main. Used for fork workflows. Result is cached for 5 minutes.

For forks, the git check is authoritative — your local package.json version will often be ahead of npm (since you're building from source), so the npm check would incorrectly say "up to date."

### Post-Merge Checklist

After a successful merge, always:

Run pnpm ui:build — the Control UI is served from dist/control-ui/
Update systemd service version — the UI header reads OPENCLAW_SERVICE_VERSION from the service unit:
NEW_VERSION=$(node -e "console.log(require('./package.json').version)")
sed -i "s/OPENCLAW_SERVICE_VERSION=.*/OPENCLAW_SERVICE_VERSION=$NEW_VERSION/" ~/.config/systemd/user/openclaw-gateway.service
systemctl --user daemon-reload


Run openclaw gateway restart — pick up the new build
Check config schema compatibility — upstream may add .strict() to schemas
Clean up backups: rm -rf /tmp/safe-merge/ — while backups are redacted, remove them when no longer needed

### 2026-03-02 — Fully Automated Pipeline

Added scripts/safe-merge-update.sh — end-to-end automated merge pipeline
Source changed from origin/main → upstream/main (now pulls real OpenClaw updates)
Fork branch updated to local-desktop-main (was main)
Conflicts auto-resolved by Claude using baked-in strategy (no human needed for happy path)
Auto-prunes stale safe-merge-* branches on each run (prevents infinite accumulation)
On success: pushes to myfork/local-desktop-main, deletes temp branch, restarts gateway
On build failure: leaves safe-merge branch intact, exits cleanly for investigation
--resume flag: skip merge, jump straight to build → push → cleanup (for post-manual-fix)
MERGE_MANIFEST.json v1.2.0: added hostinger.ts, plugins-ui.ts, memory.ts as protected files
Memory tab now shows spinner on first load (no more flash of empty content)

### 2026-03-01 — Background Sessions Panel

Added bgSessions.list and bgSessions.history RPC handlers
Added Background Sessions Panel UI (right-side drawer, session selector, live transcript, send input)
Clicking the updates badge now opens the panel alongside the update modal
State fields: bgSessionsPanelOpen, bgSessionsList, bgSessionsSelectedKey, bgSessionsHistory, bgSessionsInput, bgSessionsSending, bgSessionsHistoryLoading, bgSessionsLoading
MERGE_MANIFEST.json updated with 3 new protected files and mustPreserve patterns

### 2026-03-01 — Merge of 148 upstream commits

Conflicts resolved in: app-render.helpers.ts, app-render.ts, app-view-state.ts, app.ts. Key resolutions:

app-render.helpers.ts: kept renderContextGauge, merged hideCron + sessionsHideCron from upstream, merged countHiddenCronSessions, preserved renderRecentArchivedOptions
app-render.ts: kept our nav imports (getDynamicTabGroups, Jarvis/mode/usage); added upstream's resolveConfiguredCronModelSuggestions
app-view-state.ts: kept sessionsAgentFilter + added sessionsHideCron from upstream
app.ts: kept session history fields + added sessionsHideCron = true default from upstream

### Discord Voice Schema (2026-02-27)

Upstream added .strict() to DiscordVoiceSchema, rejecting keys our fork previously supported. Fix: remove unsupported keys from config, or add them back to the schema.

### Control UI Assets Missing (2026-02-27)

pnpm build builds the gateway but NOT the Control UI. UI needs separate pnpm ui:build. The validate script now includes this.

### Duplicate Schema Properties (2026-02-27)

Git auto-merge kept both our extracted const AND upstream's inline block. Fix: manual dedup during AI conflict resolution.

### CSP connect-src Extensions (2026-03-01)

Our fork adds http://localhost:* (Jarvis voice agent) and https://api.openai.com (Realtime API) to the CSP connect-src directive in control-ui-csp.ts. Upstream only has ws: wss:. On merge, always keep our extensions — they're required for voice features.

### Branch Naming Convention (2026-03-01)

Merge branches should be date-stamped: safe-merge-YYYY-MM-DD. This makes it easy to identify merge attempts and clean up old branches.

### Auto-Merged Protected Files Need Verification (2026-03-01)

Even files that auto-merge without conflicts can lose custom code if upstream refactors the surrounding context. After merge, always verify mustPreserve patterns exist in auto-merged protected files — don't just trust git's auto-merge.

### pnpm install May Add Packages (2026-03-01)

Upstream may add new dependencies. When 162 commits are merged, pnpm install downloaded 51 new packages. This is expected but worth noting in the merge report.

### Safety Summary

✅ Backups before any edits — /tmp/safe-merge/backups/
✅ New branch — never merges directly into current branch
✅ Validation must pass before committing
✅ No external downloads in skill setup — skill files are all local; merge workflow does use network for git fetch and pnpm install
✅ No credential requirements — uses your existing agent model
✅ Secrets redacted before model transmission — API keys, tokens, passwords, private keys
✅ Only conflict diffs sent to model — not the entire repo
✅ User controls merge — agent reports results, user decides to push
✅ Dry-run in worktree — pre-flight uses a temp worktree, not your working tree
✅ Stops on failure — if validation fails, reports and stops rather than pushing broken code
## Trust
- Source: tencent
- Verification: Indexed source record
- Publisher: maverick-software
- Version: 1.3.0
## Source health
- Status: healthy
- Source download looks usable.
- Yavira can redirect you to the upstream package for this source.
- Health scope: source
- Reason: direct_download_ok
- Checked at: 2026-04-30T16:55:25.780Z
- Expires at: 2026-05-07T16:55:25.780Z
- Recommended action: Download for OpenClaw
## Links
- [Detail page](https://openagent3.xyz/skills/safe-update-merge)
- [Send to Agent page](https://openagent3.xyz/skills/safe-update-merge/agent)
- [JSON manifest](https://openagent3.xyz/skills/safe-update-merge/agent.json)
- [Markdown brief](https://openagent3.xyz/skills/safe-update-merge/agent.md)
- [Download page](https://openagent3.xyz/downloads/safe-update-merge)