Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CONVENTIONS.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,13 @@ Fields:

Commands that bootstrap project configuration (e.g. `project-setup`) must be fully idempotent:

- **Marker comments** for CLAUDE.md sections:
- **Marker comments** for CLAUDE.md sections with content hash for update detection:
```
<!-- jj-project-setup:start -->
<!-- jj-project-setup:start hash:422ef786 -->
…content…
<!-- jj-project-setup:end -->
```
If markers exist, replace content between them. If CLAUDE.md exists without markers, prepend. If no CLAUDE.md, create it.
The hash is the first 8 chars of `md5` of the template body (content between markers). On setup: if markers exist and hash matches, skip ("already up to date"). If hash differs or markers are legacy (no hash), replace the section. If no markers, prepend. If no CLAUDE.md, create it.

- **`jq` deep-merge** for `.claude/settings.local.json` — concatenate and deduplicate arrays (`allow`, `deny`), merge objects recursively, preserve unrelated keys.

Expand Down
2 changes: 1 addition & 1 deletion plugins/commit-commands-jj/commands/commit-push-pr.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Based on the above changes:
1. `jj commit -m "<msg>"` — finalize the working copy with an appropriate description
2. Check if building on trunk: `jj log -r '@- & trunk()' --no-graph -T 'json(self) ++ "\n"'` — if this returns a result, the change is directly on trunk and needs a bookmark
3. Check if `@-` already has a bookmark: `jj log -r @- --no-graph -T 'bookmarks'`
4. If no bookmark exists on `@-`: `jj bookmark create <descriptive-name> -r @-` (use a short kebab-case name derived from the commit message)
4. If no bookmark exists on `@-`: `jj bookmark create <descriptive-name> -r @-` (use a short kebab-case name derived from the change description)
5. Push: `jj git push --bookmark <name> --allow-new`
6. Create a pull request: `gh pr create` with an appropriate title and body

Expand Down
6 changes: 3 additions & 3 deletions plugins/commit-commands-jj/commands/commit.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,12 @@ description: Finalize the current jj change with a description

## Your task

In jj, the working copy IS already a commit. The natural flow is:
In jj, the working copy IS already a change. The natural flow is:
1. Review changes in the working copy (already there — no staging needed)
2. `jj commit -m "<msg>"` — describes the current change and starts a new empty one on top

Based on the above changes, finalize the current jj change with an appropriate description.

There is no `git add` equivalent in jj. All working copy changes are automatically included. If the user needs partial commits, they should use `jj split` before running `/commit`.
There is no `git add` equivalent in jj. All working copy changes are automatically included. If the user needs to split changes, they should use `jj split` before running `/commit`.

You have the capability to call multiple tools in a single response. Create the commit using a single message. Do not use any other tools or do anything else. Do not send any other text or messages besides these tool calls.
You have the capability to call multiple tools in a single response. Finalize the change using a single message. Do not use any other tools or do anything else. Do not send any other text or messages besides these tool calls.
191 changes: 191 additions & 0 deletions plugins/commit-commands-jj/commands/finish.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
---
description: Finish development work — push+PR, squash into trunk, keep, or discard
allowed-tools: Bash(jj:*), Bash(jj git push:*), Bash(gh pr create:*), Bash(gh pr view:*), AskUserQuestion, Read
---

**CRITICAL: This is a jj (Jujutsu) plugin. You MUST NOT use ANY raw git commands — not even for context discovery. This includes git checkout, git commit, git diff, git log, git status, git add, git branch, git remote, git rev-parse, git config, git show, git fetch, git pull, git push, git merge, git rebase, git stash, git reset, git tag, or any other `git` invocation. Do not run `ls .git`, `git log`, `git remote -v` or similar to detect repo state. Always use jj equivalents (jj log, jj status, jj diff, etc.). The only exceptions are `jj git` subcommands (e.g. `jj git push`, `jj git fetch`) and `gh` CLI for GitHub operations.**

## Context

- Current change (JSON): !`jj log -r @ --no-graph -T 'json(self) ++ "\n"'`
- Parent change (JSON): !`jj log -r @- --no-graph -T 'json(self) ++ "\n"'`
- Current diff stats: !`jj diff --stat`
- Current status: !`jj status`
- Bookmarks on current change: !`jj log -r @ --no-graph -T 'bookmarks'`
- Is this a workspace?: !`jj workspace list --no-pager -T 'self.name() ++ "\n"'`

## Overview

**This skill replaces `superpowers:finishing-a-development-branch` for jj repos.**

Guide completion of development work by presenting clear options and executing the chosen workflow.

**Core principle:** Verify work exists → Present options → Execute choice → Clean up.

**Announce at start:** "I'm using the /finish skill to complete this work."

## Step 1: Verify the change has content

Check the context above. If the current change (`@`) is empty (no diff), check if `@-` has the work (common after `jj commit`). Identify the target change — the one with the actual work.

If no changes exist anywhere in the current line of work (compare against `trunk()`):
```
Nothing to finish — no changes found against trunk.
```
Stop.

If changes exist, continue. Show a brief summary of what's being finished:
```
Finishing: <description or summary of changes>
<N> files changed, +<additions>, -<deletions>
```

## Step 2: Present options

Present exactly these 4 options:

```
What would you like to do?

1. Push and create a Pull Request
2. Squash into trunk (local merge)
3. Keep as-is (I'll handle it later)
4. Discard this work
```

## Step 3: Execute choice

### Option 1: Push and create PR (most common)

1. Ensure a bookmark exists on the target change:
```bash
# Check for existing bookmark
jj log -r <target> --no-graph -T 'bookmarks'
```
If no bookmark: create one from the change description:
```bash
jj bookmark create <kebab-case-name> -r <target>
```

2. Push the bookmark:
```bash
jj git push --bookmark <name> --allow-new
```

3. Create the PR:
```bash
gh pr create --title "<title>" --body "$(cat <<'EOF'
## Summary
<2-3 bullets from the diff>

## Test plan
- [ ] <verification steps>

🤖 Generated with [Claude Code](https://claude.com/claude-code)
EOF
)"
```

4. Output the PR URL.

5. Then: Workspace cleanup (Step 4).

### Option 2: Squash into trunk (local merge)

1. Fetch latest trunk:
```bash
jj git fetch
```

2. Rebase the work onto trunk and squash:
```bash
jj rebase -r <target> -d trunk()
jj squash --into trunk() -r <target>
```

3. Verify the squash landed:
```bash
jj log -r 'trunk()' --limit 3 --no-graph
```

4. Then: Workspace cleanup (Step 4).

### Option 3: Keep as-is

Report:
```
Keeping change <change-id>. No cleanup performed.
```

**Do NOT clean up workspace.** Stop here.

### Option 4: Discard

**Confirm first:**
```
This will permanently discard:
- Change <change-id>: <description>
- <N> files changed

Type 'discard' to confirm. (Recoverable via /undo)
```

Wait for exact confirmation.

If confirmed:
```bash
jj abandon <target>
```

Then: Workspace cleanup (Step 4).

## Step 4: Workspace cleanup

**For Options 1, 2, and 4 only.**

Check if running inside a jj workspace (from context above — if workspace list shows more than just "default"):

```bash
jj workspace list --no-pager -T 'self.name() ++ "\n"'
```

If in a non-default workspace:
```bash
# Get the workspace name
# Forget the workspace from the repo
jj workspace forget <workspace-name>
```

Report what was cleaned up. If the worktree directory should be removed, note it but do NOT remove it automatically — the WorktreeRemove hook handles that.

If in the default workspace, no cleanup needed.

## Quick Reference

| Option | Push | Squash | Keep Workspace | Cleanup |
|--------|------|--------|----------------|---------|
| 1. PR | ✓ | - | ✓ | bookmark only |
| 2. Squash | - | ✓ | - | ✓ |
| 3. Keep | - | - | ✓ | - |
| 4. Discard | - | - | - | ✓ |

## Important Rules

- **Never use raw git commands.** Always jj equivalents.
- **Never force-push.** Use `jj git push` only.
- **Get typed confirmation for discard.** Always remind that `/undo` can recover.
- **Don't auto-remove worktree directories.** Let the WorktreeRemove hook handle it.
- **Keep it focused.** This skill finishes work. It does not run tests or do reviews — those are the caller's responsibility.

## Integration

**Replaces:** `superpowers:finishing-a-development-branch` in jj repos.

**Called by:**
- `superpowers:subagent-driven-development` (after all tasks complete)
- `superpowers:executing-plans` (after all batches complete)
- Manual invocation when work is done

**Pairs with:**
- `workspace-jj` — workspace creation and cleanup hooks
- `/commit-push-pr` — if you just want to push without the options menu
2 changes: 1 addition & 1 deletion plugins/commit-commands-jj/commands/show.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Show a summary of the specified revision (default: `@`).
4. If the user wants the full diff, run `jj diff -r <rev>`

Notes:
- `jj show` combines commit metadata + diff in one command
- `jj show` combines revision metadata + diff in one command
- Use `-r <rev>` to inspect any revision (change IDs, commit IDs, bookmarks, or revsets)
- The JSON metadata uses the same Commit type as `jj log`

Expand Down
2 changes: 1 addition & 1 deletion plugins/commit-commands-jj/commands/sync.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ Notes:
- `jj git fetch` auto-prunes deleted remote tracking refs
- `trunk()` is a revset that resolves to the trunk bookmark (usually `main@origin`)
- If the current change is already on trunk, the rebase is a no-op
- Conflicts in jj are first-class — they are recorded in the commit, not in the working copy
- Conflicts in jj are first-class — they are recorded in the change, not left as markers in the working copy

You have the capability to call multiple tools in a single response. Perform the sync using a single message. Do not use any other tools or do anything else. Do not send any other text or messages besides these tool calls.
13 changes: 7 additions & 6 deletions plugins/project-setup-jj/commands/project-setup.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
description: Bootstrap jj (Jujutsu) workflow enforcement for this project
allowed-tools: Bash(jj:*), Bash(cp:*), Bash(chmod:*), Bash(mkdir:*), Bash(cat:*), Bash(jq:*), Bash(ls:*), Bash(dirname:*), Bash(realpath:*), Read, Write
allowed-tools: Bash(jj:*), Bash(cp:*), Bash(chmod:*), Bash(mkdir:*), Bash(cat:*), Bash(jq:*), Bash(ls:*), Bash(dirname:*), Bash(realpath:*), Bash(md5:*), Bash(sed:*), Bash(grep:*), Read, Write
---

## Your Task
Expand Down Expand Up @@ -110,13 +110,14 @@ Replace `<project-root>` with the actual absolute path from `jj root`.

### Step 5: Create or update CLAUDE.md

Read the CLAUDE.md template from the plugin's `templates/CLAUDE.md.template`. The template is a slim policy directive (~5 lines) — not a full reference guide. It uses an `## VCS` heading (h2) so it fits naturally into any existing CLAUDE.md heading hierarchy.
Read the CLAUDE.md template from the plugin's `templates/CLAUDE.md.template`. The template includes a content hash in its start marker (`<!-- jj-project-setup:start hash:<hex> -->`) for version tracking. It uses an `## VCS` heading (h2) so it fits naturally into any existing CLAUDE.md heading hierarchy.

Then handle three cases:
Then handle four cases:

1. **No CLAUDE.md exists:** Create it from the template.
2. **CLAUDE.md exists with `<!-- jj-project-setup:start -->` marker:** Replace the section between `<!-- jj-project-setup:start -->` and `<!-- jj-project-setup:end -->` (inclusive) with the template content.
3. **CLAUDE.md exists without the marker:** Prepend the template content followed by a blank line, preserving all existing content.
2. **CLAUDE.md exists with `<!-- jj-project-setup:start hash:<hex> -->` marker:** Extract the hash from the installed marker and compare it to the hash in the template. If they match, the section is up to date — skip (report "CLAUDE.md already up to date"). If they differ, replace the section between the start and `<!-- jj-project-setup:end -->` markers (inclusive) with the template content.
3. **CLAUDE.md exists with `<!-- jj-project-setup:start -->` (no hash — legacy):** Replace the section between markers with the template content (upgrades to the hashed format).
4. **CLAUDE.md exists without any marker:** Prepend the template content followed by a blank line, preserving all existing content.

The CLAUDE.md file is at the project root (from `jj root`).

Expand All @@ -127,7 +128,7 @@ Show a summary of what was set up:
- SessionStart hook script copied to `.claude/scripts/jj-session-start.sh`
- PreToolUse guard hook copied to `.claude/scripts/require-jj-new.sh`
- Settings updated in `.claude/settings.local.json` (SessionStart hook + PreToolUse hook + permissions)
- CLAUDE.md created/updated with jj workflow instructions
- CLAUDE.md created/updated with jj workflow instructions (or "already up to date" if hash matches)

Remind the user to:
- **Restart Claude Code** for the hooks to take effect
Expand Down
10 changes: 9 additions & 1 deletion plugins/project-setup-jj/templates/CLAUDE.md.template
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
<!-- jj-project-setup:start -->
<!-- jj-project-setup:start hash:422ef786 -->
## VCS — jj (Jujutsu)

This project uses **jj (Jujutsu)** as its VCS. Never use raw git commands. Use jj equivalents instead (e.g. `jj log`, `jj status`, `jj diff`). The only exceptions are `jj git` subcommands (e.g. `jj git push`) and the `gh` CLI for GitHub operations.

### Superpowers overrides

When superpowers skills reference git-based workflows, use these jj-native replacements:

| Superpowers skill | Use instead | Why |
|---|---|---|
| `finishing-a-development-branch` | `/finish` | jj-native: bookmarks, `jj git push`, workspace cleanup |
<!-- jj-project-setup:end -->
Loading