🧪 Skills

Safe Update/Merge

Safely merge upstream OpenClaw updates without destroying plugin/skill injections, custom UI tabs, or workspace features. Two-phase: Phase 1 (automated) merg...

v1.3.0
❤️ 0
⬇️ 365
👁 1
Share

Description


name: safe-merge-update description: "Safely merge upstream OpenClaw updates without destroying plugin/skill injections, custom UI tabs, or workspace features. Two-phase: Phase 1 (automated) merges, builds, and restarts the gateway from a safe-merge branch — without touching local-desktop-main. Phase 2 (user-confirmed) promotes to local-desktop-main and pushes to the fork remote only after the user verifies the gateway is healthy." metadata: openclaw: emoji: "🔄" requires: bins: ["git"] anyPkgMgr: ["npm", "pnpm"] optionalBins: - name: "claude" description: "Claude Code CLI — only required for --auto-resolve conflict resolution. Install: npm i -g @anthropic-ai/claude-code" - name: "python3" description: "Used by preflight.sh to write the JSON report. Available by default on most Linux/macOS systems." - name: "systemctl" description: "Used to restart the gateway after a successful merge (systemctl --user restart openclaw-gateway). Required only on systemd-based Linux hosts." env: - REPO_DIR optionalEnv: - name: ANTHROPIC_API_KEY description: "Required by the claude CLI for conflict resolution. May already be set in your shell environment or claude config (~/.claude/)." - name: UPSTREAM_REMOTE description: "Git remote name for openclaw/openclaw (default: upstream)" - name: TARGET_REMOTE description: "Git remote to push result to (default: myfork)" - name: TARGET_BRANCH description: "Branch to promote on success (default: local-desktop-main)" - name: PACKAGE_MGR description: "npm or pnpm — auto-detected from lockfile if unset" gitRemotes: - name: "upstream" description: "OpenClaw upstream repo (github.com/openclaw/openclaw)" envOverride: "UPSTREAM_REMOTE" - name: "myfork" description: "Your fork remote to push to" envOverride: "TARGET_REMOTE" gitBranches: - name: "local-desktop-main" description: "Branch to promote merged result to" envOverride: "TARGET_BRANCH"

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:

Operation Phase Impact
git merge upstream/main Phase 1 Creates safe-merge-YYYY-MM-DD branch and merges — no changes to local-desktop-main
npm run build / pnpm run build Phase 1 Downloads packages if lockfile changed (network); builds in place
systemctl --user restart openclaw-gateway Phase 1 Restarts the live gateway — brief downtime; gateway now runs from safe-merge build
Conflict resolution via claude CLI Phase 1 (optional) Passes redacted file content to the Claude API; Edit+Read tools only — Bash explicitly excluded
git push --force to TARGET_REMOTE/TARGET_BRANCH Phase 2 only (--promote) Overwrites remote branch — only runs after user confirms gateway is healthy
git 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:

  1. 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
  2. Invokes the claude CLI with --allowedTools Edit,Read (no Bash) to resolve conflict markers in the redacted files — the model cannot execute shell commands
  3. After claude exits, the script runs git add -A && git commit --no-edit itself
  4. 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

Flag Description
--dry-run Fetch remotes, show divergence and estimated conflict count, then exit — no changes made
--no-auto-resolve Stop 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

Variable Default Description
REPO_DIR (required) Path to your OpenClaw repository
UPSTREAM_REMOTE upstream Remote name for openclaw/openclaw
UPSTREAM_BRANCH main Branch to pull from upstream
TARGET_REMOTE myfork Remote to force-push result to
TARGET_BRANCH local-desktop-main Branch to promote on success
LOCAL_BRANCH current branch The branch being merged from (used by preflight.sh for divergence stats)
PACKAGE_MGR auto-detect npm or pnpm (auto-detected from lockfile)

How It Works

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

Security & Privacy

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.

Invocation

Via UI

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

Via Chat

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

Architecture

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

  1. Checks you're on local-desktop-main with a clean working tree
  2. --dry-run: fetches, shows upstream divergence + estimated conflict count, exits — no changes
  3. git fetch --all
  4. Prunes any stale safe-merge-* branches (prevents accumulation)
  5. Creates safe-merge-YYYY-MM-DD branch
  6. Runs git merge upstream/main --no-edit
  7. 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
  8. pnpm build + pnpm ui:build
  9. Restarts gateway from current working tree (safe-merge branch build)
  10. Exits with confirmation promptlocal-desktop-main is unchanged, no remote push yet
  11. On build failure: leaves safe-merge branch intact for investigation

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

  1. User verifies gateway is healthy
  2. git push myfork safe-merge-YYYY-MM-DD:local-desktop-main --force
  3. git checkout local-desktop-main && git reset --hard safe-merge-YYYY-MM-DD
  4. 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

Phases

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:

  1. Create merge branchgit checkout -b safe-merge-YYYY-MM-DD
  2. Examine conflicts before merging — read both our version and upstream's version of each conflicting file to understand what each side changed
  3. Run the mergegit merge upstream/main --no-commit --no-ff
  4. 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
  5. Verify auto-merged protected files — even files that auto-merge need checking: grep for mustPreserve patterns to confirm our custom code survived
  6. 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

Variable Default Description
REPO_DIR (required, declared in metadata) Path to your OpenClaw repository
SAFE_MERGE_MODEL (agent's current model) Model override for conflict resolution
UPSTREAM_REMOTE upstream Git remote name for upstream
UPSTREAM_BRANCH main Upstream branch to merge from

Merge Model Selection

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

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

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

File Purpose
SKILL.md This file — skill instructions
MERGE_MANIFEST.json Protected files, intents, mustPreserve patterns
scripts/preflight.sh Pre-flight analysis (read-only, no modifications)
scripts/validate.sh Post-merge build and pattern validation
scripts/merge-agent-prompt.md Prompt template for per-file conflict resolution
scripts/redact-secrets.sh Secret detection and redaction before model transmission
update-modal.ts Reference copy of the UI update modal component (source of truth: ui/src/ui/views/update-modal.ts)
references/bg-sessions-backend.ts Reference: src/gateway/server-methods/bg-sessions.ts
references/bg-sessions-controller.ts Reference: ui/src/ui/controllers/bg-sessions.ts
references/bg-sessions-views.ts Reference: 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:

  1. Check for Updates — asks the user to confirm, then calls update.checkUpstream RPC with force: true (bypasses cache)
  2. Status Result — shows upstream divergence: commits behind, commits ahead, or "Up to date"
  3. 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:

  1. npm registry (update-startup.ts): Compares VERSION against npm latest. Used for standard installs.
  2. 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:

  1. Run pnpm ui:build — the Control UI is served from dist/control-ui/
  2. 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
    
  3. Run openclaw gateway restart — pick up the new build
  4. Check config schema compatibility — upstream may add .strict() to schemas
  5. Clean up backups: rm -rf /tmp/safe-merge/ — while backups are redacted, remove them when no longer needed

Changelog

2026-03-02 — Fully Automated Pipeline

  • Added scripts/safe-merge-update.sh — end-to-end automated merge pipeline
  • Source changed from origin/mainupstream/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

Known Issues / Lessons Learned

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

Reviews (0)

Sign in to write a review.

No reviews yet. Be the first to review!

Comments (0)

Sign in to join the discussion.

No comments yet. Be the first to share your thoughts!

Compatible Platforms

Pricing

Free

Related Configs