# Update

> Update BastionClaw from upstream without overwriting user data, skills, or customizations. Detects conflicts and helps merge.

- Skill: `harperaa/update` (Agent Skill)
- Install (CLI): `npx skillmds@latest add harperaa/update`
- Raw SKILL.md: https://api.skillmd.com/api/skills/harperaa/update/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: harperaa (https://skillmd.com/u/harperaa)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/harperaa/update

---


# Update BastionClaw

**UX Rule:** Use `AskUserQuestion` for ALL interactions with the user. Never just output questions as text — always use the tool so the user gets structured prompts with selectable options.

Safely update from the upstream repository while preserving all user data and customizations.

## Customization Zone Reference

BastionClaw files are organized into three zones. This skill respects these boundaries during updates.

### Green Zone — Safe to Customize (Never Overwritten)

These files are yours. Updates will never touch them.

| Location | What It Is |
|----------|-----------|
| `.env` | Secrets and configuration |
| `store/` | Database, auth sessions, all persistent data |
| `data/` | IPC files, sessions, runtime state |
| `logs/` | Host and container logs |
| `groups/*/` (except CLAUDE.md) | Group workspace files, insights, logs, conversations |
| `groups/{user-created}/` | Entire user-created group directories |
| `~/.config/bastionclaw/` | Mount allowlist (external to repo) |
| `workspace/` | YouTube transcripts, skill output |
| `.claude/projects/` | Claude Code session memory |
| `container/skills/{user-created}/` | User-added container skills |
| `.claude/skills/youtube-planner/sources.json` | Local YouTube source tracking |

### Yellow Zone — Customizable With Care (Merge on Update)

These files ship with defaults but you may have edited them. Updates will detect changes and help you merge.

| Location | What It Is | How Updates Handle It |
|----------|-----------|----------------------|
| `groups/main/CLAUDE.md` | Main group system prompt and memory | Three-way merge: your edits preserved, new upstream sections added |
| `groups/global/CLAUDE.md` | Shared memory for all groups | Same three-way merge |
| `container/skills/` (shipped ones) | Container-side skills (agent-browser, refresh-insights) | Replaced unless you edited them |
| Service files (plist/systemd) | Generated by `/setup` | Preserved if exists; regenerate with `/setup` if needed |

### Red Zone — Do Not Modify (Replaced on Update)

These files are framework code. Changes here will be overwritten on update.

| Location | What It Is |
|----------|-----------|
| `src/**/*.ts` | All host TypeScript source |
| `container/agent-runner/src/**/*.ts` | Container agent source |
| `container/Dockerfile`, `container/build.sh` | Container build files |
| `.claude/skills/*/SKILL.md` (shipped skills) | Skill definitions |
| `.claude/commands/*.md` | Slash commands |
| `scripts/*.sh`, `scripts/*.py` | Utility scripts |
| `docs/*.md` | Documentation |
| `package.json`, `package-lock.json` | Dependencies |
| `tsconfig.json`, `vitest.config.ts` | Build config |
| `ui/` | Web UI source and build |
| `.github/` | CI workflows |
| `CLAUDE.md` (root) | Project quick reference |
| `README.md` | Project documentation |

**If you need to customize Red Zone behavior**, do it through:
- **CLAUDE.md files** (Yellow Zone) — Change agent behavior, prompts, memory
- **Skills** — Add new `.claude/skills/{your-skill}/SKILL.md` directories (Green Zone, since they're new)
- **`.env`** — Configuration via environment variables (Green Zone)
- **Container skills** — Add new directories under `container/skills/` (Green Zone)

## Phase 1: Pre-flight Checks

```bash
# 1. Check we're in a git repo with the right remote
git remote -v | grep -q "bastionclaw" && echo "OK: correct repo" || echo "ERROR: not a bastionclaw repo"

# 2. Check for uncommitted changes
git status --porcelain | head -20

# 3. Get current version
node -p "require('./package.json').version"

# 4. Check the remote exists
git remote -v
```

If there are uncommitted changes, ask the user:

AskUserQuestion: "You have uncommitted changes. How should we handle them?"
- **Stash them** — `git stash` before update, `git stash pop` after (Recommended)
- **Commit first** — Create a commit with current changes before updating
- **Abort** — Stop the update, let me handle it manually

## Phase 2: Fetch and Compare

```bash
# Fetch latest from origin
git fetch origin main

# Show what's new
git log --oneline HEAD..origin/main | head -30

# Count changes
echo "$(git rev-list --count HEAD..origin/main) new commits"
```

If there are no new commits, tell the user they're already up to date and stop.

Show the user a summary of what changed:

```bash
# Files changed in the update
git diff --stat HEAD..origin/main
```

Categorize the changes by zone:

```bash
# Red Zone changes (will be applied automatically)
git diff --name-only HEAD..origin/main | grep -E '^(src/|container/agent-runner/|container/Dockerfile|container/build\.sh|scripts/|docs/|ui/|package|tsconfig|vitest|\.github/|\.claude/skills/|\.claude/commands/|CLAUDE\.md|README\.md)' | head -30

# Yellow Zone changes (need merge check)
git diff --name-only HEAD..origin/main | grep -E '^groups/(main|global)/CLAUDE\.md$|^container/skills/'

# Green Zone files (should NOT appear — if they do, flag it)
git diff --name-only HEAD..origin/main | grep -E '^(\.env|store/|data/|logs/)' && echo "WARNING: Update touches user data files!" || echo "OK: No user data files touched"
```

Present the summary to the user:

AskUserQuestion: "Here's what the update includes: [summary]. Ready to proceed?"
- **Apply update** — Merge changes, handle conflicts interactively (Recommended)
- **Review details first** — Show me the full diff before proceeding
- **Abort** — Cancel the update

## Phase 3: Detect Yellow Zone Conflicts

Before merging, check if the user has modified Yellow Zone files:

```bash
# Check if user has modified groups/main/CLAUDE.md from what we shipped
# Get the version from the merge base (what was shipped when user last updated)
MERGE_BASE=$(git merge-base HEAD origin/main)

# Check each Yellow Zone file
for file in groups/main/CLAUDE.md groups/global/CLAUDE.md; do
  if [ -f "$file" ]; then
    # Compare current file to what was in git at merge-base
    if ! git diff --quiet "$MERGE_BASE" -- "$file" 2>/dev/null; then
      echo "MODIFIED: $file (user has local changes)"
    else
      echo "CLEAN: $file (no local changes)"
    fi
  fi
done
```

For container skills, check if shipped skills have been modified:

```bash
# Check shipped container skills
for dir in container/skills/agent-browser container/skills/refresh-insights; do
  if [ -d "$dir" ]; then
    if ! git diff --quiet "$MERGE_BASE" -- "$dir" 2>/dev/null; then
      echo "MODIFIED: $dir (user has local changes)"
    fi
  fi
done
```

### Handling Yellow Zone Conflicts

For each modified Yellow Zone file that also changed upstream:

1. **Show the conflict** — Display what the user changed vs what upstream changed
2. **AskUserQuestion** with options:
   - **Keep mine** — Preserve your version, skip upstream changes to this file
   - **Take upstream** — Replace with the new upstream version (your changes are lost)
   - **Merge interactively** — Show both versions side-by-side, help combine them
   - **Merge automatically** — Attempt `git merge-file` three-way merge

For automatic merge:
```bash
# Three-way merge: base (merge-base version) + ours (current) + theirs (upstream)
git show "$MERGE_BASE:$file" > /tmp/base_version
git show "origin/main:$file" > /tmp/upstream_version
cp "$file" /tmp/our_version

# Attempt merge
git merge-file /tmp/our_version /tmp/base_version /tmp/upstream_version

if [ $? -eq 0 ]; then
  echo "Clean merge — no conflicts"
  cp /tmp/our_version "$file"
else
  echo "Merge has conflicts — needs manual resolution"
  # Show conflict markers to user
  cat /tmp/our_version
fi
```

## Phase 4: Apply the Update

```bash
# Create a safety tag before updating
git tag "pre-update-$(date +%Y%m%d-%H%M%S)" HEAD

# Merge origin/main
git merge origin/main --no-edit
```

If the merge has conflicts:

```bash
# Show conflicted files
git diff --name-only --diff-filter=U
```

For each conflicted file:
- **Red Zone files**: Accept the upstream version (`git checkout --theirs <file>`)
- **Yellow Zone files**: Use the interactive merge from Phase 3
- **Green Zone files**: Should not conflict (flag if they do — something is wrong)

After resolving all conflicts:

```bash
git add -A && git commit --no-edit
```

## Phase 5: Post-Update Tasks

Run these in order:

```bash
# 1. Install any new/updated dependencies
npm install

# 2. Build TypeScript
npm run build

# 3. Check for new skills
ls .claude/skills/ | sort

# 4. Check if container needs rebuild
git diff --name-only "pre-update-*"..HEAD -- container/ | head -5
```

If container files changed:
```bash
# Rebuild the container image
./container/build.sh
```

If UI files changed:
```bash
cd ui && npm install && npm run build && cd ..
```

### Database Migrations

Check if the update includes schema changes:

```bash
# Look for migration-related changes in db.ts
git diff "$(git describe --tags --abbrev=0 --match 'pre-update-*')"..HEAD -- src/db.ts | grep -E 'CREATE TABLE|ALTER TABLE|CREATE INDEX' | head -10
```

If schema changes are detected, inform the user. The `initDatabase()` function handles migrations automatically on restart — but mention it so they know.

### Restart the Service

```bash
./scripts/restart.sh --build
```

## Phase 6: Verify

```bash
# 1. Check new version
node -p "require('./package.json').version"

# 2. Check build is clean
npm run build 2>&1 | tail -3

# 3. Check service is running
tail -5 logs/bastionclaw.log

# 4. Unstash if we stashed in Phase 1
git stash list | head -3
```

If we stashed changes in Phase 1:
```bash
git stash pop
```

If the stash pop has conflicts, help the user resolve them.

## Rollback

If anything goes wrong, the user can roll back:

```bash
# Find the safety tag
git tag -l 'pre-update-*' | sort | tail -1

# Roll back to it
git reset --hard <tag-name>
npm install && npm run build
./scripts/restart.sh --build
```

Tell the user about this option if any step fails.

