| name | fork-maintenance |
| description | 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. |
Fork Maintenance
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.
The Pattern
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.
- Feature/fix branches are parents of sami, never children. All development happens on these branches.
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.
Decision: Where Does This Change Go?
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
Checking if a Bug is Upstream
git show dev:path/to/file.tsx | sed -n 'START,ENDp'
jj file show sami:path/to/file.tsx | sed -n 'START,ENDp'
Finding Which Branch Changed a 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
Creating a New Branch
jj log --no-graph -T 'change_id.shortest(4) ++ " " ++ description.first_line() ++ "\n"' \
-r 'parents(parents(sami))' | sort | uniq -c | sort -rn | head -5
jj new <common-base> -m "fix(scope): description"
jj bookmark set fix/my-fix
Adding a Branch to Sami
jj rebase -s sami -d "all:sami- ~ <old_parent_if_replacing>" -d <new_branch>
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"
jj log --no-graph -T 'conflict' -r sami
Removing a Branch from Sami
When a branch is merged upstream or no longer needed:
jj rebase -s sami -d "all:sami- ~ <branch_to_remove>"
Modifying an Existing Branch
To add fixes to a branch that's already a sami parent:
jj new feat/voice-mode -m "fix(app): additional fix"
jj bookmark set feat/voice-mode
Syncing with Upstream
jj git fetch
jj rebase -b <branch> -d <new-common-base>
jj git fetch && jj log --no-graph -T 'conflict' -r sami
Conflict Resolution in Octopus Merges
When sami has conflicts after adding/removing parents or syncing:
-
Check what's conflicted:
jj new sami
jj status
-
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
Continuous Conflict Monitor
When parents are being rebased by other agents:
- Run
jj workspace update-stale every 3 minutes
- Check for new conflicts:
jj log --no-graph -T 'conflict' -r sami
- If conflicts appear, resolve them
- If your commit was split by jj, squash the pieces back together
Stop monitoring after 15 minutes with no new conflicts.
Build & Deploy (Web Frontend)
If the fork includes a web frontend:
deploy-web
deploy-web --local
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.
Manual Build
jj new sami
cd packages/app && bun run build
grep "unique_string_from_your_change" dist/assets/*.js
rm -rf ~/opencode-web-frontend && cp -r dist ~/opencode-web-frontend
caddy reload --config ~/.dotfiles/opencode-web/Caddyfile
curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:8080/
Orientation
Run jj-agent-status to see the repo state: current position, active agents, branches, divergent/conflicted changes, and what needs attention.
Before You Start: Research
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
After Code Changes: Verification
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.
bun test
-
Push and check CI. After pushing, monitor CI status. Don't walk away.
jj git push
gh pr checks
-
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.
Definition of Done
Work on a fork branch is complete when ALL of these are true:
Common Pitfalls
- Basing a branch on
dev@upstream instead of common-base โ lockfile conflicts in sami. Always use the same base as existing branches.
- Committing on sami instead of a branch โ can't be merged upstream, hard to isolate. Always work on named branches.
- Forgetting to deploy โ code changes are invisible in the web app. Always
deploy-web after frontend changes.
- Leaving changes as sami children โ they should be on a named branch that's a sami parent. Rebase onto the right branch.
- Using
jj rebase with change IDs when divergent changes exist โ use commit IDs instead, or the all:sami- revset pattern.
- Cross-branch conflicts aren't inherited โ resolving conflicts in individual parent branches does NOT resolve the octopus merge. Sibling branches can conflict with each other in ways not visible in either parent. Verify the merge separately.
- Never typecheck a conflicted working copy โ conflict markers are syntax errors. Typecheck per-branch after resolving each one, not on the merge with markers.
- Never hand-merge lockfiles โ
bun.lock, package-lock.json, yarn.lock are generated. Delete and run the package manager to regenerate.
- Never edit a conflicted jj change directly โ use
jj new <conflicted>, resolve in the child, then jj squash back. This preserves change identity.
- Verify files exist before investigating โ if you're debugging a feature, check the files exist in your current checkout first. They may only be in the merge or a specific branch.
- jj conflict format:
+++++++ = snapshot (full file state), %%%%%%% = diff (branch's changes to apply). For semantic merges, preserve the diff side's intent.
- "Done" means deployed โ code changes in jj branches are invisible until built and deployed. For web UI changes, run
deploy-web and verify your code is in the bundle.