Blog

A jj-Native Hub for Claude Code on the Web

May 15, 2026 · Oskar Austegard

There's now a third hub template for Claude Code on the Web: claude-jjithub-and-spoke. It boots a CCotw session with jj (Jujutsu) installed, an identity seeded from your GitHub PAT, and a git credential helper wired up so that jj git clone and jj git push work against any of your GitHub repos — without the token landing in URLs or in .git/config.

It's a sibling of two earlier templates that follow the same shape from the hub-and-spoke post:

Each template pairs a forge with a VCS and whatever CLI fits the forge's collaboration model. The new one is the jj-shaped variant of the first.

Why no gh pr create

jj's GitHub story is opinionated. There is no jj pr create verb, and that's deliberate — not a TODO. The model is that bookmarks are the named refs a PR points at, so the prescribed loop is: push a bookmark, open the PR in the GitHub web UI, merge there, then jj git fetch to advance trunk locally. The CLI's job ends at the push.

The agent's loop on a spoke looks like this:

jj git clone https://github.com/owner/repo .spokes/repo
cd .spokes/repo
jj new main
# … edit …
jj describe -m "fix: handle empty input"
jj bookmark create feature-x -r @
jj git push --bookmark feature-x
echo "Review: https://github.com/owner/repo/compare/main...feature-x"

Claude stops at that echo. You click the compare URL, GitHub turns it into a PR draft, you review, you merge. Back on the spoke, jj git fetch advances local main to the merged tip.

An earlier draft of the template's CLAUDE.md called the hub "PR-free." That was wrong, and it got corrected the same day: these are still PRs, opened and merged in GitHub like any other. The constraint is that the agent doesn't open the PR, and there's no gh in the container to tempt it. If you want Claude to drive the PR end-to-end, use claude-github-and-spoke. This template trades that for jj's working-copy ergonomics and jj op log — an operation log that makes "undo whatever you just did" a single command, which is the recovery primitive that earns jj its keep in an agent context.

What's in the template

FilePurpose
boot.shInstalls jj from the upstream tarball, writes ~/.config/jj/config.toml, wires the git credential helper
.claude/settings.jsonSessionStart hook + denies the built-in GitHub MCP server (it only sees the hub repo and duplicates a jj-shaped workflow anyway)
bin/ghiStdlib (no external deps) CLI for GitHub Issues — list, view, create, comment, close. The issues surface the no-gh rule otherwise leaves on the floor
skills/jj/SKILL.mdjj mental model, command reference, recovery primitives — loaded into the session
CLAUDE.mdAgent-facing recipes and the compare-URL hand-off, plus the .spokes/ clone-path constraint that keeps the commit-signing helper happy

The naming, since several people have asked: jjithub = jj (the binary name) + jit (audible middle of jiu-jitsu) + hub (the architecture word). Three-layer fold mirroring github = git + hub, with the doubled j as a nod to jj-vcs.

Quick start

Click the green Use this template → Create a new repository button on the repo page, drop a GH_TOKEN into .env (repo scope is enough), then open your new repo in Claude Code on the Web. The SessionStart hook does the rest.