pi-jj #
A Pi extension that shows where you are in a jj repository.
The footer shows the working-copy change, the nearest bookmark below it, what the change touches, and how many changes have unresolved conflicts:
jj rxptmqkv · main+3 · 1 file +1 -1 · 1 conflicted
main+3: the nearest bookmarked ancestor, and how many changes sit on top of it.1 file +1 -1: files and lines changed in@. An unchanged@shows its flags (conflict,divergent,empty) instead.1 conflicted: mutable changes with conflicts; hidden when there are none.
In a repo with several workspaces, the
footer starts with the one Pi's working directory is in. stale marks a
stale working copy, whose files
may not match @ until jj workspace update-stale runs:
jj w2@ rxptmqkv · stale · main+3 · 1 file +1 -1
Each shell command the agent runs starts in that directory, so a cd into another workspace lasts
only for that command and doesn't change what the footer shows. To work in another workspace, move
the session there instead (see below).
/jj toggles a panel above the editor with the workspace and its root (when there are several),
then @ and each parent: change and commit IDs, bookmarks, description, diff size, and flags.
The display refreshes when the session starts, after each tool call, when the agent finishes, and
shortly after ! shell commands. Outside a jj repo nothing is shown.
Workspaces #
/jj workspace <name> [revision] [--forget] moves the conversation into a workspace of the current repo,
creating it if it doesn't exist. A new workspace's change starts on revision, or by default on the
parents of the current @, as with jj workspace add. /jj workspace on its own picks an existing
workspace, including default to go back. If the agent is running, the move waits until it finishes.
In interactive sessions in a jj repo, the agent can do the same with the jj_workspace tool. The move
happens once its turn ends, and the agent then continues in the workspace; aborting the turn cancels
it.
With --forget (the tool's forget option), the workspace being left is dropped once the session has
moved: jj workspace forget runs in it, which records its files first, and the directory is deleted if
pi-jj created it. Changes jj tracks stay in the repo, while ignored files such as installed
dependencies go with the directory. Finishing work in a workspace therefore means bringing those
changes onto a bookmark (and pushing) as usual, then moving back with --forget. The workspace that
holds the repository can't be forgotten, nor can a stale one until jj workspace update-stale has run
in it.
Moving copies the conversation, with its full history, into a new session whose working directory is
the workspace, so files, shell commands, AGENTS.md, and the footer all follow. With Pi's default
session directories, the copy is filed under the workspace: /resume in the original project shows it
only in its "All" view, and pi -c there continues the conversation from before the move. A custom
session directory keeps the copy. Sessions started with --no-session can't move.
New workspaces go under $XDG_DATA_HOME/pi-jj/workspaces/ (by default ~/.local/share/...), one
directory per repo, rather than next to or inside the project, where searches and builds would pick
them up. They hold only tracked files: reinstall dependencies there as needed. To remove one without
moving, run jj workspace forget <name>, then delete its directory.
If the project has .pi/ resources that need project trust, Pi asks
for it again in each new workspace directory.
Commit signing #
Each refresh runs jj, which records file changes into @. With signing.behavior = "own", every
such rewrite is signed, so a signer that asks for confirmation (such as 1Password or a hardware key)
prompts after nearly every edit. To sign once per push instead, use jj's
sign-on-push:
[signing]
behavior = "drop"
# keep your existing backend and key settings
[git]
sign-on-push = true
jj git push then signs the unsigned commits it pushes. Commits that are never pushed stay unsigned.
Install #
pi install https://tangled.org/did:plc:cyg36pmc7siatajaomwcb3bu/
Or try it for one session with pi -e <path-to-checkout>.
Requires jj on PATH.
Development #
npm install
npm run check # type-check
npm test # runs against temporary jj repos