The core idea is simple: one jj change becomes one GitHub PR, and your local history defines the stack. Reorder, split, squash, or amend locally with ordinary jj commands, run jj-stack submit again, and the existing PRs update in place with their reviews intact. It uses GitHub's native stacked PRs, and handles merging and the local cleanup afterwards.
The heavy lifting was in its safety model. Local jj history and GitHub can each change without the other knowing, and an interrupted submit or network flap can leave part of a stack updated. Someone can squash-merge or rebase your stack from the GitHub UI, which might strip the metadata jj uses to recognise changes. jj-stack checks both sides before it acts, verifies rebased stacks by ancestry and file content, and acts carefully. A large share of the test suite (including an extensive Hypothesis property test suite) exists to exercise these cases.