plugins/sjawhar/skills/fork-maintenance/SKILL.md
Use when working on a forked repository that uses an octopus merge (sami) to combine feature branches. This skill covers triaging where changes belong in a fork (which branch? new branch? upstream PR?), managing octopus merge parents (add, remove, rebase), resolving multi-parent merge conflicts, syncing with upstream, and verifying work is ready to ship. Load this skill whenever you need to decide where a fix or feature should go in a fork repo, manage the octopus merge structure, check if fork work is complete (am I done?, what is left to ship?), or follow the contribution lifecycle (push, CI, reviews, deploy). Also triggers on: sami, octopus merge, fork triage, which branch does this go on, rebase fork, existing issues, check CI.
npx skillsauth add sjawhar/dotfiles fork-maintenanceInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
This user maintains forks using an octopus merge pattern: a merge commit (typically called sami) that combines independent feature/fix branches as parents. Each fork also has a ci branch for build workflows. This pattern is used across multiple repos, not just one.
sami (octopus merge, N parents)
├── feat/voice-mode branch off common-base
├── feat/web-perf-optimize branch off common-base
├── fix/session-blank-render branch off common-base
├── ci build workflow
└── ... more feature/fix branches
sami is the integration point. It has no code changes of its own — just combines parents.ci branch holds CI/build workflow changes.common-base is the commit most branches share as their parent (often the last upstream release or a known-good upstream commit). Using the same base avoids conflicts when combining into sami.When you need to make a change, the first question is always: where does it belong?
Is this a bug in upstream code (identical in dev)?
├── YES → New fix/ branch off common-base → add as sami parent
└── NO → Is this a bug in one of our branches?
├── YES → Fix on that branch (child commit, move bookmark)
└── NO → Is this a new feature?
├── YES → New feat/ branch off common-base → add as sami parent
└── NO → Is this a CI/build change?
└── YES → Fix on the ci branch
# Compare our code with upstream dev
git show dev:path/to/file.tsx | sed -n 'START,ENDp' # upstream
jj file show sami:path/to/file.tsx | sed -n 'START,ENDp' # ours
# If identical → upstream bug, new branch off common-base
# If different → our bug, fix on the branch that changed it
# Check each sami parent for changes to a specific file
for parent in $(jj log --no-graph -T 'change_id.shortest(8) ++ "\n"' -r 'parents(sami)'); do
changed=$(jj diff --stat -r "$parent" 2>/dev/null | grep "path/to/file" | wc -l)
if [ "$changed" -gt 0 ]; then
desc=$(jj log --no-graph -T 'description.first_line()' -r "$parent")
echo "$parent: $desc"
fi
done
# Find common-base (the parent most branches share)
# Look at existing branches to identify it:
jj log --no-graph -T 'change_id.shortest(4) ++ " " ++ description.first_line() ++ "\n"' \
-r 'parents(parents(sami))' | sort | uniq -c | sort -rn | head -5
# Create branch off common-base
jj new <common-base> -m "fix(scope): description"
# Make changes, typecheck
# ...
# Set bookmark
jj bookmark set fix/my-fix
# Method 1: Using revset (clean, handles divergent changes)
jj rebase -s sami -d "all:sami- ~ <old_parent_if_replacing>" -d <new_branch>
# Method 2: Using commit IDs (when divergent changes cause issues)
PARENTS=$(jj log --no-graph -T 'parents.map(|p| "-o " ++ p.commit_id().short(12)).join(" ")' -r sami)
NEW=$(jj log --no-graph -T 'commit_id.short(12)' -r <new_branch>)
eval "jj rebase -r sami $PARENTS -o $NEW"
# Verify conflict-free
jj log --no-graph -T 'conflict' -r sami # Should print: false
When a branch is merged upstream or no longer needed:
jj rebase -s sami -d "all:sami- ~ <branch_to_remove>"
To add fixes to a branch that's already a sami parent:
# Create child of the branch
jj new feat/voice-mode -m "fix(app): additional fix"
# Make changes...
# Move bookmark to new tip
jj bookmark set feat/voice-mode
# Sami auto-rebases since its parent changed
# Verify: jj log --no-graph -T 'conflict' -r sami
jj git fetch
# Rebase all feature branches onto new upstream:
# For each branch, rebase onto the new common-base
jj rebase -b <branch> -d <new-common-base>
# OR if you just want to update sami's view of upstream:
# Fetch and verify no new conflicts appeared in sami
jj git fetch && jj log --no-graph -T 'conflict' -r sami
When sami has conflicts after adding/removing parents or syncing:
Check what's conflicted:
jj new sami # Create child to work in
jj status # See conflicted files
Understand the conflict: Octopus merge conflicts often have more than 2 sides. Read all conflict markers carefully.
Resolve: Load the resolve-conflicts skill for detailed conflict resolution strategy. The key insight for octopus merges: conflicts are usually from lockfiles or version bumps, not logic conflicts. For lockfiles, regenerate rather than merge.
Squash resolution into sami:
jj squash # Moves resolution from @ into sami (parent)
When parents are being rebased by other agents:
jj workspace update-stale every 3 minutesjj log --no-graph -T 'conflict' -r samiStop monitoring after 15 minutes with no new conflicts.
If the fork includes a web frontend:
deploy-web # Pull latest CI build from gh-pages
deploy-web --local # Build from current sami checkout
After ANY web UI code change, deploy. Code changes in jj branches are invisible until built and deployed. This is the #1 source of "it doesn't work" reports.
jj new sami # Checkout sami merge
cd packages/app && bun run build # Build
# Verify your code is in the bundle:
grep "unique_string_from_your_change" dist/assets/*.js
# Deploy:
rm -rf ~/opencode-web-frontend && cp -r dist ~/opencode-web-frontend
caddy reload --config ~/.dotfiles/opencode-web/Caddyfile
# Smoke test:
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/
Run jj-agent-status to see the repo state: current position, active agents, branches, divergent/conflicted changes, and what needs attention.
Before writing any code, do your homework. This saves hours of wasted work:
Search existing issues and PRs. Someone may have already fixed this, or there may be an open discussion about the right approach. Check both the upstream repo and the fork.
gh issue list --search "blank session render" --state all
gh pr list --search "session resume" --state all
Check upstream for related changes. If you're fixing a bug, upstream may have already fixed it in a newer version. Check recent commits:
git log dev --oneline --since='2 weeks ago' -- path/to/file.tsx
Read the repo's AGENTS.md and CLAUDE.md. These contain project-specific conventions, build commands, test commands, and deployment processes. Every repo is different.
Understand the repo's PR and issue conventions. Some repos have title formats, templates, required labels, or linked issues. Check existing PRs for the pattern:
gh pr list --state merged --limit 5
Code passing typecheck is necessary but not sufficient. Before declaring work done:
Run tests locally. Don't push untested code and wait for CI to tell you it's broken.
# Check the repo's AGENTS.md for the exact test command
bun test # or npm test, cargo test, etc.
Push and check CI. After pushing, monitor CI status. Don't walk away.
jj git push
gh pr checks # or gh run list
Read automated review comments. Many repos have bots (Sentry, CodeRabbit, Copilot, custom reviewers) that leave comments on PRs. These are a form of CI — read them.
gh pr view --comments
Follow the repo's deployment process. Check AGENTS.md for how this software gets deployed. For web apps, there's usually a build + deploy step. For libraries, it might be a publish step. For services, it might be a deploy command or CI pipeline.
Verify in production. After deploying, verify your change is actually live. For web apps, check the bundle contains your code. For APIs, hit the endpoint. Don't assume deploy succeeded.
Work on a fork branch is complete when ALL of these are true:
dev@upstream instead of common-base → lockfile conflicts in sami. Always use the same base as existing branches.deploy-web after frontend changes.jj rebase with change IDs when divergent changes exist → use commit IDs instead, or the all:sami- revset pattern.bun.lock, package-lock.json, yarn.lock are generated. Delete and run the package manager to regenerate.jj new <conflicted>, resolve in the child, then jj squash back. This preserves change identity.+++++++ = snapshot (full file state), %%%%%%% = diff (branch's changes to apply). For semantic merges, preserve the diff side's intent.deploy-web and verify your code is in the bundle.development
Use when searching flights, hotels, or rental cars; comparing fares across flexible dates; discovering cheap destinations from a fixed origin; or hunting hidden-city ticketing deals. Trigger on multi-city itineraries, fare calendars, "where can I fly cheaply", price-sensitive trip planning, or any time the user wants a sanity-check against Google Flights pricing — Skiplagged surfaces hidden-city deals other engines deliberately hide.
development
Search the web via Ceramic Search (lexical/keyword-based). Use when looking up current events, recent news, time-sensitive facts, specific people/products/companies, technical docs, or any topic requiring fresh web results. Triggers on "search the web", "look up", "find recent", "latest news", "current", or when built-in knowledge is likely stale.
tools
Use when reading WhatsApp messages, searching conversations, sending messages, listing chats, or interacting with WhatsApp workspaces
tools
Watch CI status, fix failures, and merge when green