Add CUPS print server container for Brother HL-4150CDN
This commit is contained in:
commit
6f3162849b
52 files changed
+5168
No files matched your search
@@ -0,0 +1,333 @@
|
||||
---
|
||||
name: jujutsu
|
||||
description: Use this skill for any version control operations (commit, log, diff, push, fetch, bookmark, workspace, rebase, undo, etc.). If a `.jj` directory exists, the repo is jujutsu and git mutations will corrupt it — use `jj` for all mutations; read-only `git log/diff/show/blame/grep` are allowed. Covers co-located repos, multi-agent parallel workspaces, and operation-log recovery. **DO NOT IGNORE**
|
||||
allowed-tools: Bash(jj *)
|
||||
license: Apache-2.0
|
||||
metadata:
|
||||
author: johnstegeman
|
||||
version: "1.3"
|
||||
---
|
||||
|
||||
# Jujutsu (jj) Version Control System
|
||||
|
||||
This skill helps you work with Jujutsu, a Git-compatible VCS with mutable commits and automatic rebasing.
|
||||
|
||||
**Tested with jj v0.41.0** - Commands may differ in other versions.
|
||||
|
||||
For token-sensitive inspection commands, prefer the compact commands in `references/TEMPLATES.md` over jj's default output.
|
||||
|
||||
The compact commands in `references/TEMPLATES.md` intentionally use `jj --no-pager ...`.
|
||||
|
||||
For revsets, filesets, and template syntax, see `references/QUERY_LANGUAGES.md`.
|
||||
|
||||
For sibling or unrelated work that should start from `trunk()`, see `references/NONLINEAR.md`.
|
||||
|
||||
For common surprises and easy mistakes, see `references/GOTCHAS.md`.
|
||||
|
||||
<!--
|
||||
Attribution and inspiration sources:
|
||||
|
||||
- Forked from danverbraganza/jujutsu-skill (https://skills.sh/danverbraganza/jujutsu-skill/jujutsu).
|
||||
The original scaffolding, references/ structure, and core mental-model wording are from there.
|
||||
|
||||
- Enforcement language in "Critical: never use git for mutations" was tightened using the
|
||||
read-only-git allowlist pattern from knoopx/pi@jujutsu
|
||||
(https://skills.sh/knoopx/pi/jujutsu).
|
||||
|
||||
- "Parallel Workspaces" framing as a tool for multi-agent isolation draws on
|
||||
onevcat/skills@onevcat-jj (https://skills.sh/onevcat/skills/onevcat-jj),
|
||||
which is explicitly subtitled "Version Control for Agent Workflows".
|
||||
|
||||
- The .workspaces/ project-local directory convention, the .gitignore safety check,
|
||||
and the directory-selection priority documented in references/WORKSPACES.md
|
||||
come from edmundmiller/dotfiles using-jj-workspaces
|
||||
(https://lobehub.com/skills/edmundmiller-dotfiles-using-jj-workspaces).
|
||||
|
||||
- The "op log records every mutation; nothing is ever truly lost" framing in the
|
||||
Recovery section is adapted from trevors/dot-claude@jj-workflow
|
||||
(https://skills.sh/trevors/dot-claude/jj-workflow).
|
||||
|
||||
- Query-language guidance, nonlinear-work patterns, and workspace handoff /
|
||||
monitoring ideas were adapted from joshuadavidthomas/agent-skills `jj`
|
||||
(https://github.com/joshuadavidthomas/agent-skills/tree/main/jj) and its
|
||||
`workspaces.md`
|
||||
(https://raw.githubusercontent.com/joshuadavidthomas/agent-skills/main/jj/workspaces.md),
|
||||
while intentionally preserving this skill's local describe-first workflow and
|
||||
`.workspaces/` / `workspaces/` directory priority.
|
||||
-->
|
||||
|
||||
|
||||
## Detecting a jj repo
|
||||
|
||||
Check whether a directory is part of a jj repo:
|
||||
|
||||
```bash
|
||||
jj root
|
||||
```
|
||||
|
||||
If it returns a path, the repo is jj-managed. If it returns `Error: There is no jj repo in <directory>`, it isn't. The presence of a `.jj/` folder is another giveaway. If the repo is not a jj one, do not further use this skill.
|
||||
|
||||
<!-- Enforcement wording (allowed/forbidden split with read-only git allowlist) adapted from knoopx/pi@jujutsu. -->
|
||||
## Critical: never use git for mutations in a jj repo
|
||||
|
||||
In a jj repo (including co-located repos that also have `.git/`):
|
||||
|
||||
- **Forbidden** (corrupts jj state): `git commit`, `git add`, `git stash`, `git reset`, `git checkout <branch>`, `git switch`, `git rebase`, `git merge`, `git cherry-pick`, `git push`, `git pull`.
|
||||
- **Allowed** (read-only): `git log`, `git show`, `git diff`, `git blame`, `git grep`, `git status`. Prefer the `jj` equivalents (`jj log`, `jj show`, `jj diff`, etc.) but read-only git commands won't break anything.
|
||||
- **Use jj instead**: `jj git push`, `jj git fetch`, `jj edit <change>` (not `git checkout`), `jj rebase`, `jj new <a> <b>` (for merges).
|
||||
|
||||
See `references/COLOCATED.md` for the full co-located repo workflow.
|
||||
|
||||
## Important: Automated/Agent Environment
|
||||
|
||||
When running as an agent or running on behalf of the user:
|
||||
|
||||
1. **Always use `-m` flags** to provide commit messages inline rather than relying on editor prompts:
|
||||
|
||||
```bash
|
||||
# Always use -m to avoid editor prompts
|
||||
jj desc -m "message" # NOT: jj desc
|
||||
jj squash --into @- -m "message" # NOT: jj squash (which opens editor or prompts for hunks)
|
||||
```
|
||||
|
||||
Editor-based commands will fail in non-interactive environments.
|
||||
|
||||
2. **Verify operations with `jj st`** after mutations (`squash`, `abandon`, `rebase`, `restore`) to confirm the operation succeeded.
|
||||
|
||||
## Important Principles
|
||||
|
||||
1. Each commit should represent one logical change. See [commit messages](references/COMMIT_MSG.md) for details on good commit messages. Before starting work on a new change, make sure the working copy is clean (no changes)
|
||||
|
||||
```bash
|
||||
jj st
|
||||
```
|
||||
|
||||
## Core Concepts
|
||||
|
||||
### The Working Copy is a Commit
|
||||
|
||||
In jj, your working directory is always a commit (referenced as `@`). Changes are automatically snapshotted when you run any jj command. There is no staging area.
|
||||
|
||||
There is no need to run `jj commit`.
|
||||
|
||||
### Commits Are Mutable
|
||||
|
||||
**CRITICAL**: Unlike git, jj commits can be freely modified. This enables a high-quality commit workflow:
|
||||
|
||||
1. Before starting work, run `jj st`. If `@` already has changes, run `jj new` first. If `@` is empty, use it as-is.
|
||||
2. Describe your intended changes with `jj desc -m "Message"`
|
||||
3. Make your changes.
|
||||
4. Do NOT run `jj new` when finished — leave that to the next task's step 1.
|
||||
|
||||
You may refine the commit using `jj squash` or `jj absorb` as needed
|
||||
|
||||
### Change IDs vs Commit IDs
|
||||
|
||||
- **Change ID**: A stable identifier (like `tqpwlqmp`) that persists when a commit is rewritten
|
||||
- **Commit ID**: A content hash (like `3ccf7581`) that changes when commit content changes
|
||||
|
||||
Prefer using Change IDs when referencing commits in commands.
|
||||
|
||||
## Essential Workflow
|
||||
|
||||
### Starting Work: Describe First, Then Code
|
||||
|
||||
**Always create your commit message before writing code:**
|
||||
|
||||
```bash
|
||||
# First, describe what you intend to do
|
||||
jj desc -m "feat: Add user authentication to login endpoint"
|
||||
|
||||
# Then make your changes - they automatically become part of this commit
|
||||
# ... edit files ...
|
||||
|
||||
# Check status
|
||||
jj st
|
||||
```
|
||||
|
||||
For the full starting-a-change workflow (when to reuse `@` vs `jj new`, anti-patterns, decision logic), see `references/NEW_CHANGE.md`.
|
||||
|
||||
For unrelated or sibling work that should branch from `trunk()`, see `references/NONLINEAR.md`.
|
||||
|
||||
### Creating Atomic Commits
|
||||
|
||||
Each commit should represent ONE logical change.
|
||||
|
||||
### Viewing History
|
||||
|
||||
```bash
|
||||
# View recent commits
|
||||
jj log
|
||||
|
||||
# View with patches
|
||||
jj log -p
|
||||
|
||||
# View specific commit
|
||||
jj show <change-id>
|
||||
|
||||
# View diff of working copy
|
||||
jj diff
|
||||
```
|
||||
|
||||
If you need to run `jj log`, `jj show`, or `jj diff` as an agent, use the matching compact command from `references/TEMPLATES.md` unless the full default output is explicitly needed.
|
||||
|
||||
For the revsets, filesets, and template syntax behind those compact commands, see `references/QUERY_LANGUAGES.md`.
|
||||
|
||||
### Moving Between Commits
|
||||
|
||||
```bash
|
||||
# Create a new empty commit on top of current
|
||||
jj new
|
||||
|
||||
# Create new commit with message
|
||||
jj new && jj desc -m "Commit message"
|
||||
|
||||
# Edit an existing commit (working copy becomes that commit)
|
||||
jj edit <change-id>
|
||||
|
||||
# Edit the previous commit
|
||||
jj prev -e
|
||||
|
||||
# Edit the next commit
|
||||
jj next -e
|
||||
```
|
||||
|
||||
## Refining Commits
|
||||
|
||||
If you need to refine a commit (squash, abandon, undo, split, etc), see (Refining commits)[references/REFINE_COMMIT.md]
|
||||
|
||||
## Working with Bookmarks (Branches)
|
||||
|
||||
Bookmarks are jj's equivalent to git branches:
|
||||
|
||||
```bash
|
||||
# Create a bookmark at current commit
|
||||
jj bookmark create my-feature -r@
|
||||
|
||||
# Move bookmark to a different commit
|
||||
jj bookmark move my-feature --to <change-id>
|
||||
|
||||
# List bookmarks
|
||||
jj bookmark list
|
||||
|
||||
# Delete a bookmark
|
||||
jj bookmark delete my-feature
|
||||
```
|
||||
|
||||
If you need to run `jj bookmark list`, use the matching compact command from `references/TEMPLATES.md`.
|
||||
|
||||
<!--
|
||||
Multi-agent workspace framing inspired by onevcat/skills@onevcat-jj.
|
||||
The .workspaces/ project-local convention codified in references/WORKSPACES.md
|
||||
is adapted from edmundmiller/dotfiles using-jj-workspaces.
|
||||
-->
|
||||
## Parallel Workspaces
|
||||
|
||||
For running multiple agents in parallel against the same repo without working-copy collisions, use `jj workspace`. Each workspace gets its own `@` while sharing the underlying repo store.
|
||||
|
||||
```bash
|
||||
# Quick reference (full convention in references/WORKSPACES.md)
|
||||
jj workspace add .workspaces/<repo>-<purpose> # Create
|
||||
jj workspace list # List
|
||||
jj workspace forget <name> # Untrack (files stay on disk)
|
||||
```
|
||||
|
||||
If you need to run `jj workspace list`, use the matching compact command from `references/TEMPLATES.md`.
|
||||
|
||||
See `references/WORKSPACES.md` for the full convention: the `.workspaces/` directory layout, `.gitignore` safety check, naming, environment bootstrapping, agent handoff, monitoring, stale-workspace recovery, and merging results from multiple workspaces back together.
|
||||
|
||||
## Working with tags
|
||||
|
||||
jujutsu does not yet support tags and pushing them to a remote. If you need to tag (such as for a release), you will need to use git to create and push the tags.
|
||||
|
||||
## Git Integration (Co-located Repos)
|
||||
|
||||
Always use co-located repos when working with existing git projects. They give you jj locally while keeping the repo remote-compatible with git tooling.
|
||||
|
||||
```bash
|
||||
jj git clone <url> --colocate # Clone a git repo
|
||||
jj git init --colocate # Adopt an existing git repo
|
||||
```
|
||||
|
||||
See `references/COLOCATED.md` for the complete workflow: the mutation rule (`git` is forbidden for mutations, allowed read-only), the git-command allowlist, common gotchas, and switching modes when absolutely necessary.
|
||||
|
||||
See `references/GOTCHAS.md` when the behavior feels surprising and you want the short list of jj-specific footguns before trying a git-style workaround.
|
||||
|
||||
### Pushing Changes
|
||||
|
||||
For pushing bookmarks to a remote, see `references/PUSH.md`. For named remotes, fork+upstream setups, and other multi-remote workflows, see `references/REMOTES.md`.
|
||||
|
||||
## Handling Conflicts
|
||||
|
||||
jj treats conflicts as first-class objects — a commit can contain a conflict, and that conflict persists through rebases until resolved. `jj` refuses to push conflicted commits, so they must be resolved before `jj git push`.
|
||||
|
||||
```bash
|
||||
jj st # Reports if @ has unresolved conflicts
|
||||
jj resolve --list # Lists conflicted paths
|
||||
jj resolve --tool :ours # Take side #1 non-interactively (agent-safe)
|
||||
jj resolve --tool :theirs # Take side #2 non-interactively (agent-safe)
|
||||
```
|
||||
|
||||
**Never run bare `jj resolve` (no `--tool`)** — it's interactive and will hang in non-interactive agent environments. Either pass `--tool :ours` / `--tool :theirs`, or edit conflict markers directly in the file and let `jj st` snapshot the resolution.
|
||||
|
||||
See `references/CONFLICTS.md` for the full resolution playbook: marker formats (diff vs snapshot), five resolution paths, ancestor-level resolution to avoid re-resolving across descendants, verification (beyond `jj st`), and anti-patterns.
|
||||
|
||||
<!-- Recovery framing ("op log records every mutation; nothing is ever lost") adapted from trevors/dot-claude@jj-workflow. -->
|
||||
## Recovery and the Operation Log
|
||||
|
||||
The op log records every mutation. Nothing is ever lost.
|
||||
|
||||
```bash
|
||||
jj undo # Reverse the last operation (primary recovery tool)
|
||||
jj op log # See all operations
|
||||
jj op restore <op-id> # Jump back to any past state
|
||||
jj evolog -r <change> # See how a specific change evolved
|
||||
```
|
||||
|
||||
If you need to run `jj op log` or `jj evolog`, use the matching compact commands from `references/TEMPLATES.md` first. Add `-p` only after you have narrowed the scope.
|
||||
|
||||
**Always reach for `jj undo` first** when something looks wrong — it's always correct and safe. See `references/RECOVERY.md` for recovery patterns by scenario (bad squash, accidental abandon, lost work, etc.).
|
||||
|
||||
## Preserving Commit Quality
|
||||
|
||||
**IMPORTANT**: Because commits are mutable, always refine them:
|
||||
|
||||
1. **Review your commit**: `jj show @` or `jj diff`
|
||||
2. **Is it atomic?** One logical change per commit
|
||||
3. **Is the message clear?** Use imperative verb phrase in sentence case format with no full stop: "Verb object"
|
||||
4. **Are there unrelated changes?** Use `jj restore` to move changes out, then create separate commits
|
||||
5. **Should changes be elsewhere?** Use `jj squash` or `jj absorb`
|
||||
|
||||
## Quick Reference
|
||||
|
||||
| Action | Command |
|
||||
|--------|---------|
|
||||
| Describe commit | `jj desc -m "message"` |
|
||||
| View status | `jj st` |
|
||||
| View log | `jj log` |
|
||||
| View diff | `jj diff` |
|
||||
| New commit | `jj st` then `jj new` only if `@` has changes, then `jj desc -m "message"` |
|
||||
| Edit commit | `jj edit <id>` |
|
||||
| Squash to parent | `jj squash --into @- -m "message"` |
|
||||
| Auto-distribute | `jj absorb` |
|
||||
| Abandon commit | `jj abandon <id>` |
|
||||
| Undo last operation | `jj undo` |
|
||||
| Restore files | `jj restore [paths]` |
|
||||
| Create bookmark | `jj bookmark create <name>` |
|
||||
| Push bookmark | `jj git push -b <name>` |
|
||||
| Add workspace | `jj workspace add .workspaces/<repo>-<purpose>` |
|
||||
| List workspaces | `jj workspace list` |
|
||||
| Forget workspace | `jj workspace forget <name>` |
|
||||
| See operation log | `jj op log` |
|
||||
| Jump to past state | `jj op restore <op-id>` |
|
||||
| See change evolution | `jj evolog -r <id>` |
|
||||
|
||||
## Best Practices Summary
|
||||
|
||||
1. **Describe first**: Set the commit message before coding
|
||||
2. **One change per commit**: Keep commits atomic and focused
|
||||
3. **Use change IDs**: They're stable across rewrites
|
||||
4. **Refine commits**: Leverage mutability for clean history
|
||||
5. **Embrace the workflow**: No staging area, no stashing — the op log replaces both
|
||||
6. **Workspaces for parallel agents**: Isolate concurrent agent work in `.workspaces/<repo>-<purpose>` (see `references/WORKSPACES.md`)
|
||||
7. **`jj undo` first**: When something looks wrong, undo before fixing manually (see `references/RECOVERY.md`)
|
||||
@@ -0,0 +1,4 @@
|
||||
interface:
|
||||
display_name: "Jujutsu"
|
||||
short_description: "Help with Jujutsu version control workflows"
|
||||
default_prompt: "Use $jujutsu to inspect this repo, choose the right jj workflow, and carry the change through safely."
|
||||
@@ -0,0 +1,81 @@
|
||||
# Co-located jj + git Repositories
|
||||
|
||||
A **co-located** repo has both `.jj/` and `.git/` at the same root. jj manages local operations; git stays in sync underneath so remote-side tooling (CI, GitHub, hooks, IDE plugins, `gh` CLI) continues to work normally.
|
||||
|
||||
This is the **strongly recommended** setup for working with an existing git project.
|
||||
|
||||
## Why co-located
|
||||
|
||||
- **Local: jj's superior model.** Mutable commits, no staging area, the op log as a safety net.
|
||||
- **Remote: still git.** GitHub sees ordinary commits and refs. Collaborators don't need to know you use jj.
|
||||
- **Tooling parity.** IDE git integrations, pre-commit hooks, `gh`/`git` CLI for read-only inspection all continue to work.
|
||||
|
||||
## Creating a co-located repo
|
||||
|
||||
```bash
|
||||
# From scratch
|
||||
jj git init --colocate
|
||||
|
||||
# From a remote
|
||||
jj git clone <url> --colocate
|
||||
|
||||
# Adopt an existing git repo (run from inside it)
|
||||
cd existing-git-repo
|
||||
jj git init --colocate
|
||||
```
|
||||
|
||||
After this, both `.jj/` and `.git/` exist and stay synchronized automatically. **Never run `jj git init` without `--colocate`** on a project you already have git history for — non-colocated init creates a separate git store inside `.jj/repo/store/git` which is harder to work with.
|
||||
|
||||
## The mutation rule
|
||||
|
||||
> **Never use `git` for mutations in a co-located jj repo.** Read-only `git` is fine.
|
||||
|
||||
| git command | Allowed in jj repo? |
|
||||
|---|---|
|
||||
| `git log`, `git show`, `git diff`, `git blame`, `git grep` | ✅ Allowed (jj equivalents preferred) |
|
||||
| `git status` | ✅ Allowed (shows git's view; may differ from `jj st`) |
|
||||
| `git commit`, `git add`, `git stash`, `git reset` | ❌ Forbidden — corrupts jj state |
|
||||
| `git checkout <branch>`, `git switch` | ❌ Forbidden — use `jj edit` instead |
|
||||
| `git rebase`, `git merge`, `git cherry-pick` | ❌ Forbidden — use `jj rebase`, `jj new <a> <b>`, `jj duplicate` |
|
||||
| `git fetch` | ⚠️ Use `jj git fetch` — it keeps jj in sync |
|
||||
| `git pull` | ❌ Forbidden — `git pull` does fetch+merge; use `jj git fetch` + `jj rebase` |
|
||||
| `git push` | ❌ Forbidden — use `jj git push -b <bookmark>` |
|
||||
|
||||
The reason: jj snapshots the working copy on every jj command. If git mutates state behind jj's back, jj's next snapshot will be confused about what changed when, and the op log can get out of sync.
|
||||
|
||||
## Switching to git mode (rare; usually a smell)
|
||||
|
||||
If you genuinely need to use a git workflow for one operation (e.g., an external tool insists), do it carefully:
|
||||
|
||||
```bash
|
||||
# 1. Ensure jj working copy is committed and clean
|
||||
jj st
|
||||
# (resolve anything pending — describe, refine, etc.)
|
||||
|
||||
# 2. Now run the git operation
|
||||
git <something>
|
||||
|
||||
# 3. Return to jj — jj will re-sync on the next command
|
||||
jj st # Triggers re-sync
|
||||
jj edit <change-id> # Resume work
|
||||
```
|
||||
|
||||
**Almost every git operation has a jj equivalent that's safer.** Reach for git mode only as a last resort.
|
||||
|
||||
## Common gotchas
|
||||
|
||||
- **Git complains about uncommitted changes**: jj's working copy is always a commit; git sees that as "uncommitted." Use `jj st` (not `git status`) to assess state.
|
||||
- **HEAD detachment**: jj manages `HEAD` per change. `git checkout` will detach HEAD in confusing ways — use `jj edit` instead.
|
||||
- **`.gitignore` is respected by jj** automatically. `.jjignore` is only needed if you want jj-only ignore patterns the outer git doesn't see.
|
||||
- **Branches vs bookmarks**: git branches become jj bookmarks on fetch. Bookmarks don't auto-advance like git branches — you must `jj bookmark move` before pushing.
|
||||
|
||||
## Pushing from a co-located repo
|
||||
|
||||
Use `jj git push`, not `git push`:
|
||||
|
||||
```bash
|
||||
jj bookmark move main --to @ # Move bookmark to your latest change
|
||||
jj git push -b main # Push to remote
|
||||
```
|
||||
|
||||
See `references/PUSH.md` for the full push workflow.
|
||||
@@ -0,0 +1,25 @@
|
||||
# Creating good commit messages
|
||||
|
||||
1. Use the following format:
|
||||
|
||||
```
|
||||
<type>: <subject>
|
||||
|
||||
<body>
|
||||
```
|
||||
The valid <type> values are: fix, feat, chore, docs
|
||||
Type and subject are required
|
||||
Body is optional
|
||||
|
||||
2. If there is a body, separate it from the subject with a blank line
|
||||
3. Limit the subject line to 50 characters. This is not a hard limit but a rule of thumb. The subject line should explain the "what" of the logical change
|
||||
4. Capitalize the subject line
|
||||
5. Do not end the subject line with a period
|
||||
6. Use the imperative mood in the subject line
|
||||
Imperative mood just means “spoken or written as if giving a command or instruction”. A few examples:
|
||||
|
||||
* Clean your room
|
||||
* Close the door
|
||||
* Take out the trash
|
||||
7. Wrap the body at 72 characters
|
||||
8. Use the body to explain what and why vs. how
|
||||
@@ -0,0 +1,176 @@
|
||||
# Resolving Conflicts
|
||||
|
||||
jj treats conflicts as **first-class objects**: a commit can contain a conflict, and that conflict **persists through rebases** until someone resolves it. This is the headline mental-model difference from git, where a working tree must be conflict-free before committing.
|
||||
|
||||
For an agent, this changes the rhythm:
|
||||
|
||||
- A `jj rebase` or `jj squash` that produces a conflict **does not fail**. It succeeds; the resulting commit is just marked conflicted.
|
||||
- You can keep working — even keep rebasing the conflicted commit further — and resolve it later.
|
||||
- `jj` won't let you push a conflicted commit to a remote, so conflicts must be resolved before `jj git push`.
|
||||
|
||||
## Detecting conflicts
|
||||
|
||||
```bash
|
||||
jj st # Shows "There are unresolved conflicts" if any
|
||||
jj resolve --list # Lists all conflicted paths in @
|
||||
jj resolve --list -r <change-id> # Lists conflicts in a specific change
|
||||
jj log # Conflicted changes are shown with a "conflict" marker
|
||||
```
|
||||
|
||||
## Conflict marker formats
|
||||
|
||||
jj supports three marker styles (set via `ui.conflict-marker-style`):
|
||||
|
||||
- **`diff`** (modern default) — shows base→side as a diff
|
||||
- **`snapshot`** — full content of each side, like git's `<<<<<<<` style
|
||||
- **`git`** — legacy git-compatible 3-way
|
||||
|
||||
Check your style:
|
||||
|
||||
```bash
|
||||
jj config get ui.conflict-marker-style
|
||||
```
|
||||
|
||||
### Example: `diff` style
|
||||
|
||||
```
|
||||
<<<<<<< Conflict 1 of 1
|
||||
%%%%%%% Changes from base to side #1
|
||||
-base content here
|
||||
+side 1 content here
|
||||
+++++++ Contents of side #2
|
||||
side 2 content here
|
||||
>>>>>>> Conflict 1 of 1 ends
|
||||
```
|
||||
|
||||
- Side #1 = "ours" (the destination — typically your current branch/change)
|
||||
- Side #2 = "theirs" (the source — typically what's being rebased/merged in)
|
||||
- The `%%%%%%%` block shows what side #1 changed *from the common base*; side #2's content is shown directly.
|
||||
|
||||
### Example: `snapshot` style
|
||||
|
||||
```
|
||||
<<<<<<< Conflict 1 of 1
|
||||
+++++++ Contents of side #1
|
||||
side 1 content here
|
||||
%%%%%%% Contents of base
|
||||
base content here
|
||||
+++++++ Contents of side #2
|
||||
side 2 content here
|
||||
>>>>>>> Conflict 1 of 1 ends
|
||||
```
|
||||
|
||||
Both styles delimit conflict regions identically. To resolve: replace the entire `<<<<<<< ... >>>>>>>` block with the desired final content.
|
||||
|
||||
## Five resolution paths (agent-friendly)
|
||||
|
||||
`jj resolve` with no `--tool` launches an interactive merge tool and **will hang in non-interactive agent environments**. Use one of these instead:
|
||||
|
||||
### 1. Edit conflict markers directly (most common)
|
||||
|
||||
Read the file, replace each `<<<<<<<` block with the resolved content, save. Then snapshot:
|
||||
|
||||
```bash
|
||||
jj st # Triggers snapshot; should report no remaining conflicts
|
||||
```
|
||||
|
||||
This is the canonical agent path. Works for any merge complexity.
|
||||
|
||||
### 2. Take one side wholesale: `:ours` / `:theirs`
|
||||
|
||||
For conflicts where one side simply wins (e.g., a rebase brings in unrelated formatting changes you don't want):
|
||||
|
||||
```bash
|
||||
jj resolve --tool :ours # Keep side #1; drop side #2's conflicting changes
|
||||
jj resolve --tool :theirs # Keep side #2; drop side #1's conflicting changes
|
||||
|
||||
# Scope to specific paths
|
||||
jj resolve --tool :ours path/to/file.rs
|
||||
```
|
||||
|
||||
These built-in tools are **non-interactive** and safe to use in agent contexts. They apply to all conflicts in `@` (or the paths given).
|
||||
|
||||
### 3. Restore from a specific version: `jj restore --from`
|
||||
|
||||
When neither side is right but a *different* revision has the content you want:
|
||||
|
||||
```bash
|
||||
jj restore --from <change-id> path/to/file.txt
|
||||
```
|
||||
|
||||
This pulls the file contents from `<change-id>` into the working copy, replacing conflict markers entirely.
|
||||
|
||||
### 4. Abandon a hopelessly conflicted change
|
||||
|
||||
If the conflicted change wasn't worth keeping:
|
||||
|
||||
```bash
|
||||
jj abandon <change-id>
|
||||
```
|
||||
|
||||
Descendants are rebased onto the parent. Their own conflicts (if any) remain to be resolved separately.
|
||||
|
||||
### 5. Resolve at the ancestor, let jj re-propagate
|
||||
|
||||
If a rebase produced the same conflict in many descendants, **don't resolve each descendant individually**. Resolve once at the change where the conflict first appeared, and jj will re-propagate the resolution forward:
|
||||
|
||||
```bash
|
||||
# Find where the conflict first appeared
|
||||
jj log -r 'conflicts()'
|
||||
|
||||
# Edit that change directly
|
||||
jj edit <ancestor-change-id>
|
||||
# ... fix conflict markers ...
|
||||
jj st # Snapshot the resolution
|
||||
jj edit @- # Move back to where you were
|
||||
```
|
||||
|
||||
Descendants pick up the resolution automatically.
|
||||
|
||||
## Verifying a resolution
|
||||
|
||||
After editing, **don't trust `jj st` alone**:
|
||||
|
||||
```bash
|
||||
# 1. Status should report no conflicts
|
||||
jj st
|
||||
|
||||
# 2. Grep for residual markers (catches typos that left markers in place)
|
||||
git grep -E '^(<{7}|>{7}|\\%{7}|\\+{7})' || echo 'no residual conflict markers'
|
||||
|
||||
# 3. Run the project's tests/linter — markers may be syntactically valid in some
|
||||
# languages (e.g. inside strings) and parse-tests catch what eyeballing misses.
|
||||
```
|
||||
|
||||
In a colocated repo, `git grep` is allowed (read-only). In a non-colocated repo, use `grep -rE` or `rg`.
|
||||
|
||||
## Pushing conflicted commits is blocked
|
||||
|
||||
```bash
|
||||
jj git push -b main
|
||||
# Refused: branch main contains conflicts
|
||||
```
|
||||
|
||||
You'll need to resolve before pushing. There's no `--force-push-conflicts` option — this is by design.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- ❌ **`jj resolve` (no `--tool`)** — interactive; will hang the agent. Always pass `--tool :ours` / `--tool :theirs` or edit markers manually.
|
||||
- ❌ **Resolving descendants individually after a rebase** — wasteful and error-prone; resolve at the ancestor (path 5).
|
||||
- ❌ **Relying on `jj st` to verify resolution** — also grep for residual markers and run tests.
|
||||
- ❌ **Trying to `git checkout` to "drop" a conflict** in a colocated repo — corrupts jj state. Use `jj abandon` or resolve.
|
||||
- ❌ **`jj squash` to "hide" a conflict into another commit** — the conflict propagates; it doesn't disappear.
|
||||
|
||||
## Quick reference
|
||||
|
||||
| Action | Command |
|
||||
|---|---|
|
||||
| List conflicts in `@` | `jj resolve --list` |
|
||||
| List conflicts everywhere | `jj log -r 'conflicts()'` |
|
||||
| Resolve manually | Edit file, then `jj st` |
|
||||
| Take "ours" (side #1) | `jj resolve --tool :ours [paths...]` |
|
||||
| Take "theirs" (side #2) | `jj resolve --tool :theirs [paths...]` |
|
||||
| Restore from another rev | `jj restore --from <change-id> <path>` |
|
||||
| Drop the change | `jj abandon <change-id>` |
|
||||
| Find conflict's ancestor | `jj log -r 'conflicts() ~ ::conflicts()-'` |
|
||||
| Check marker style | `jj config get ui.conflict-marker-style` |
|
||||
@@ -0,0 +1,47 @@
|
||||
# Gotchas
|
||||
|
||||
Short list of jj behaviors that regularly surprise agents.
|
||||
|
||||
**Tested with jj 0.41.0**
|
||||
|
||||
## 1. Working Copy Is a Commit
|
||||
|
||||
`@` is always a commit, not a staging area. `jj new` starts a different change; it does not finish the current one.
|
||||
|
||||
## 2. Most jj Commands Snapshot the Working Copy
|
||||
|
||||
Running `jj st`, `jj log`, and many other commands can record filesystem changes into the working-copy commit. If you intentionally need a stale view, use `--ignore-working-copy`.
|
||||
|
||||
## 3. Change IDs and Commit IDs Are Different
|
||||
|
||||
Change IDs are stable across rewrites. Commit IDs change whenever content or metadata changes. Prefer change IDs when handing work to another agent.
|
||||
|
||||
## 4. `jj undo` Is the First Recovery Tool
|
||||
|
||||
Do not manually reverse a bad `rebase`, `squash`, or `abandon` before trying `jj undo`. Use `references/RECOVERY.md` for deeper recovery.
|
||||
|
||||
## 5. Pager Output Is Not a Good Agent Default
|
||||
|
||||
Use the compact commands in `references/TEMPLATES.md`. Those commands intentionally use `jj --no-pager ...`.
|
||||
|
||||
## 6. Co-located Repos Still Forbid Git Mutations
|
||||
|
||||
`git log`, `git show`, `git diff`, `git blame`, `git grep`, and `git status` are fine. `git commit`, `git add`, `git rebase`, `git push`, and similar mutations can corrupt jj state.
|
||||
|
||||
## 7. `jj workspace forget` Does Not Delete Files
|
||||
|
||||
It only unregisters the workspace. Delete the directory separately if cleanup is intended.
|
||||
|
||||
## 8. Stale Workspaces Are Normal in Parallel Work
|
||||
|
||||
If another workspace rewrites your base, use `jj workspace update-stale`. Verify the result with `jj st` instead of improvising a manual repair.
|
||||
|
||||
## 9. Bare `jj resolve` Is Interactive
|
||||
|
||||
For agent-safe conflict handling, use `jj resolve --tool :ours`, `jj resolve --tool :theirs`, or edit conflict markers directly.
|
||||
|
||||
## 10. Default Output Is Often Too Large
|
||||
|
||||
Prefer compact templates, targeted revsets, and narrow filesets before reaching for full `jj log -p` or `jj show`.
|
||||
|
||||
When behavior feels surprising, stop and check `references/NEW_CHANGE.md`, `references/TEMPLATES.md`, `references/WORKSPACES.md`, or `references/RECOVERY.md` before inventing a git-style workaround.
|
||||
@@ -0,0 +1,49 @@
|
||||
# Starting a New Change
|
||||
|
||||
The jj workflow is: **describe first, then code, then refine**. The working copy is always a commit (`@`), so you're already in one when you start. The question is whether to reuse it or start fresh.
|
||||
|
||||
## The opening sequence
|
||||
|
||||
```bash
|
||||
# 1. Check what @ currently looks like
|
||||
jj st
|
||||
```
|
||||
|
||||
**If `@` is empty** (no changes, no description set, or description is fine to discard):
|
||||
- Reuse it. Just describe and start.
|
||||
|
||||
**If `@` has changes you want to keep** (it's someone else's WIP, or work you haven't finished):
|
||||
- Start fresh with `jj new` — this creates a new empty commit on top of `@`.
|
||||
|
||||
```bash
|
||||
# 2. Describe before coding (only with -m; never editor-based)
|
||||
jj desc -m "feat: Add user authentication to login endpoint"
|
||||
|
||||
# 3. Make changes — they snapshot to @ automatically on the next jj command
|
||||
# (no `jj add`, no `jj commit` needed)
|
||||
|
||||
# 4. Verify
|
||||
jj st
|
||||
```
|
||||
|
||||
## Why describe first
|
||||
|
||||
Setting the message up front:
|
||||
- Forces you to articulate the change as one logical unit before writing code (atomic commits)
|
||||
- Means there's never a phase where `@` says "(no description set)"
|
||||
- Makes the change navigable in `jj log` while it's still being built
|
||||
|
||||
See `references/COMMIT_MSG.md` for the message format conventions.
|
||||
|
||||
## After the change is done
|
||||
|
||||
**Do NOT run `jj new` to "close" the change.** In jj, the working copy is always a commit — there's no separate commit step. Leave `@` as-is; the *next* task's step 1 (`jj st` → reuse or `jj new`) handles transition.
|
||||
|
||||
If refinement is needed (split, squash, absorb, abandon), see `references/REFINE_COMMIT.md`.
|
||||
|
||||
## Anti-patterns
|
||||
|
||||
- ❌ `jj commit` — doesn't exist; the working copy is already a commit
|
||||
- ❌ `jj desc` without `-m` — opens an editor; will hang in non-interactive agent environments
|
||||
- ❌ Running `jj new` at the end of a task — leaves an empty `@` for the next agent to clean up
|
||||
- ❌ Starting code before describing — you'll forget to describe, or describe vaguely after the fact
|
||||
@@ -0,0 +1,65 @@
|
||||
# Nonlinear Work
|
||||
|
||||
This skill supports sibling commits and unrelated work. Do not force everything onto the current stack if the work is logically independent.
|
||||
|
||||
**Tested with jj 0.41.0**
|
||||
|
||||
## When to Start a Sibling from `trunk()`
|
||||
|
||||
Use a fresh sibling when:
|
||||
|
||||
- `@` already represents one logical change and the new work is unrelated
|
||||
- the user wants multiple independent lines of work
|
||||
- you need to compare or merge two alternative implementations
|
||||
- a quick fix appears while a feature change is already in progress
|
||||
|
||||
## Preferred Flow
|
||||
|
||||
This skill keeps the local "describe first" rule, even for sibling work:
|
||||
|
||||
```bash
|
||||
jj st
|
||||
jj new trunk()
|
||||
jj desc -m "fix: handle stale workspace recovery"
|
||||
# make changes
|
||||
jj st
|
||||
```
|
||||
|
||||
Use `trunk()` instead of guessing `main` or `master`. If the new work should build on the current change, use plain `jj new` instead of `jj new trunk()`.
|
||||
|
||||
## Child vs Sibling
|
||||
|
||||
Use a child (`jj new`) when:
|
||||
|
||||
- the new work depends on the current change
|
||||
- the user wants a stacked sequence
|
||||
- the current commit is intentionally being split into follow-up commits
|
||||
|
||||
Use a sibling from `trunk()` when:
|
||||
|
||||
- the work should review, land, or be abandoned independently
|
||||
- you are branching off to do an unrelated fix, doc change, or experiment
|
||||
- parallel agents need clearly separated lines of history
|
||||
|
||||
## Merge-Shaped Work
|
||||
|
||||
If two independently meaningful lines of work should remain visible as a merge, create an explicit merge commit:
|
||||
|
||||
```bash
|
||||
jj new <left-change> <right-change> -m "merge: combine related lines of work"
|
||||
```
|
||||
|
||||
Ask the user before choosing between:
|
||||
|
||||
- rebasing one line onto the other
|
||||
- keeping a visible merge
|
||||
- pushing each line separately
|
||||
|
||||
## Anti-Patterns
|
||||
|
||||
- Do not keep piling unrelated work into the current `@` just because it is convenient.
|
||||
- Do not adopt a `describe -> code -> jj new -> repeat` loop. In this skill, `jj new` starts the next change; it does not close the current one.
|
||||
- Do not default to `jj new trunk() --no-edit -m ...` here. Keep the local sequence: choose the base first, then run `jj desc -m ...`.
|
||||
- Do not hardcode `main` or `master` when `trunk()` expresses the intent.
|
||||
|
||||
See `references/NEW_CHANGE.md` for the default change-starting workflow and `references/WORKSPACES.md` for multi-workspace parallelism.
|
||||
@@ -0,0 +1,38 @@
|
||||
### Pushing Changes
|
||||
|
||||
When the user asks you to push changes:
|
||||
|
||||
```bash
|
||||
# Push a specific bookmark to the remote
|
||||
jj git push -b <bookmark-name>
|
||||
|
||||
# Example: push the main bookmark
|
||||
jj git push -b main
|
||||
```
|
||||
|
||||
**Before pushing, ensure:**
|
||||
1. Your bookmark points to the correct commit (bookmarks don't auto-advance like git branches)
|
||||
2. The commits are refined and atomic
|
||||
3. The user has explicitly requested the push
|
||||
|
||||
**IMPORTANT**: Unlike git branches, jj bookmarks do not automatically move when you create new commits. You must manually update them before pushing:
|
||||
|
||||
```bash
|
||||
# Move an existing bookmark to the current commit
|
||||
jj bookmark move my-feature --to @
|
||||
|
||||
# Then push it
|
||||
jj git push -b my-feature
|
||||
```
|
||||
|
||||
If no bookmark exists for your changes, create one first:
|
||||
|
||||
```bash
|
||||
# Create a bookmark at the current commit
|
||||
jj bookmark create my-feature
|
||||
|
||||
# Then push it
|
||||
jj git push -b my-feature
|
||||
```
|
||||
|
||||
For named remotes, multi-remote setups (e.g. fork + upstream), tracking remote bookmarks, and one-time configuration for the two canonical multi-remote workflows, see `references/REMOTES.md`.
|
||||
@@ -0,0 +1,91 @@
|
||||
# Query Languages
|
||||
|
||||
Use jj's query languages when you need to select revisions, paths, or render compact output without falling back to the default verbose UI.
|
||||
|
||||
**Tested with jj 0.41.0**
|
||||
|
||||
## Revsets
|
||||
|
||||
Use revsets to select commits and workspaces.
|
||||
|
||||
Common selectors:
|
||||
|
||||
- `@`: current working-copy change
|
||||
- `@-`: parent of the current working-copy change
|
||||
- `trunk()`: configured mainline; use this instead of guessing `main` vs `master`
|
||||
- `::@`: all ancestors of `@`
|
||||
- `trunk()..@`: work reachable from `@` that is not on `trunk()`
|
||||
- `working_copies()`: all workspace working-copy commits
|
||||
- `<workspace>@`: another workspace's working-copy commit
|
||||
- `<change-id>`: a stable change ID such as `wqzktpqm`
|
||||
|
||||
Agent patterns:
|
||||
|
||||
```bash
|
||||
# Current work relative to trunk
|
||||
jj --no-pager log -r 'trunk()..@'
|
||||
|
||||
# All active workspace tips
|
||||
jj --no-pager log -r 'working_copies()'
|
||||
|
||||
# One specific workspace tip
|
||||
jj --no-pager log -r '<workspace>@'
|
||||
```
|
||||
|
||||
Quote revsets that contain punctuation or function calls.
|
||||
|
||||
## Filesets
|
||||
|
||||
Use filesets when a command should operate on only part of the tree.
|
||||
|
||||
Common patterns:
|
||||
|
||||
- `path` or `"path"`: cwd-relative path prefix
|
||||
- `file:"path"`: exact cwd-relative file path
|
||||
- `glob:"pattern"`: cwd-relative glob
|
||||
- `root:"path"`: workspace-relative path prefix
|
||||
- `~x`: everything except `x`
|
||||
- `x & y`: intersection
|
||||
- `x | y`: union
|
||||
- `x ~ y`: subtract `y` from `x`
|
||||
|
||||
Examples:
|
||||
|
||||
```bash
|
||||
# Only markdown files in the current directory
|
||||
jj diff 'glob:"*.md"'
|
||||
|
||||
# Everything in src except snapshots
|
||||
jj diff 'src ~ glob:"src/**/*.snap"'
|
||||
|
||||
# Exact file path
|
||||
jj diff 'file:"README.md"'
|
||||
```
|
||||
|
||||
## Templates
|
||||
|
||||
Use templates when default output is too large or too decorative for agent work.
|
||||
|
||||
Common building blocks:
|
||||
|
||||
- `++`: concatenate output pieces
|
||||
- `if(cond, a, b)`: conditional formatting
|
||||
- `description.first_line()`: one-line summary
|
||||
- `change_id.shortest(8)`: stable short ID
|
||||
- `bookmarks`: bookmark names for a commit
|
||||
- `current_working_copy`, `empty`, `conflict`: useful booleans in `jj log`
|
||||
|
||||
Example:
|
||||
|
||||
```bash
|
||||
jj --no-pager log --no-graph -n 5 -T 'change_id.shortest(8) ++ " " ++ if(description, description.first_line(), "(no description)") ++ "\n"'
|
||||
```
|
||||
|
||||
Start from `references/TEMPLATES.md` instead of inventing new templates unless you need something substantially different.
|
||||
|
||||
## Rules
|
||||
|
||||
- Prefer `trunk()` over hardcoding `main` or `master`.
|
||||
- Quote revsets and filesets in shell commands when punctuation could be interpreted by the shell.
|
||||
- Prefer compact `jj --no-pager` inspection commands before widening the query.
|
||||
- If a query fails to parse, check `jj <command> --help`, `jj help -k revsets`, `jj help -k filesets`, or `jj help -k templates`.
|
||||
@@ -0,0 +1,118 @@
|
||||
# Recovery and the Operation Log
|
||||
|
||||
The **operation log** records every mutation to the repo — every `jj` command that changed state. Nothing is ever truly lost. This is jj's safety net: an agent that makes a mistake (bad squash, accidental abandon, wrong rebase) can always go back.
|
||||
|
||||
## The three recovery primitives
|
||||
|
||||
### 1. `jj undo` — reverse the last operation
|
||||
|
||||
```bash
|
||||
jj undo
|
||||
```
|
||||
|
||||
The first thing to reach for. Reverses the most recent operation atomically — works for `abandon`, `squash`, `rebase`, `restore`, `describe`, and most other mutations.
|
||||
|
||||
**Prefer `jj undo` over manually reversing changes** — it's always correct and safe.
|
||||
|
||||
### 2. `jj op log` — see the full operation history
|
||||
|
||||
```bash
|
||||
jj op log # All operations, newest first
|
||||
jj op log -n 20 # Limit to 20
|
||||
jj op log -p # Include diffs of what each op changed
|
||||
```
|
||||
|
||||
If you are inspecting first and do not yet need full diffs, start with the compact `jj op log` command from `references/TEMPLATES.md`. Add `-p` only after you have narrowed the relevant op IDs.
|
||||
|
||||
Each operation has an `op-id`. Use these to navigate further back than a single `jj undo`.
|
||||
|
||||
### 3. `jj op restore` — jump to any past state
|
||||
|
||||
```bash
|
||||
jj op restore <op-id>
|
||||
```
|
||||
|
||||
Restores the entire repo to the state it was in at that op. **This is the nuke-from-orbit recovery** — it can undo many operations at once. Safe because the restore itself becomes a new op in the log (you can `jj undo` it if you change your mind).
|
||||
|
||||
## Per-change history: `jj evolog`
|
||||
|
||||
The op log shows everything; `jj evolog` shows how a *single change* evolved (was rewritten, squashed into, rebased, etc.):
|
||||
|
||||
```bash
|
||||
jj evolog # Evolution of the current @
|
||||
jj evolog -r <change-id> # Evolution of a specific change
|
||||
jj evolog -p # Include patches between versions
|
||||
```
|
||||
|
||||
If you are inspecting first and do not yet need patches, start with the compact `jj evolog` command from `references/TEMPLATES.md`. Add `-p` only after you have narrowed the relevant version.
|
||||
|
||||
Useful when you want to recover an earlier *version* of a specific commit (e.g., "what did this commit look like before I squashed into it?").
|
||||
|
||||
## Common recovery scenarios
|
||||
|
||||
### Accidentally abandoned the wrong change
|
||||
|
||||
```bash
|
||||
jj undo # If it was just now
|
||||
# or
|
||||
jj op log # Find the abandon op
|
||||
jj op restore <op-id> # Restore to before it
|
||||
```
|
||||
|
||||
### A `jj squash` merged work into the wrong parent
|
||||
|
||||
```bash
|
||||
jj undo # Single-step undo
|
||||
```
|
||||
|
||||
If you've done more work since:
|
||||
|
||||
```bash
|
||||
jj op log # Locate the squash op
|
||||
jj op restore <op-id> # Jump back; ops after that point are dropped
|
||||
```
|
||||
|
||||
### A rebase went sideways
|
||||
|
||||
```bash
|
||||
jj undo # Reverse the rebase entirely
|
||||
```
|
||||
|
||||
### Lost work after a complex sequence
|
||||
|
||||
```bash
|
||||
jj op log -p # Diffs show exactly what each op did
|
||||
# Find the op id where the work still existed
|
||||
jj op restore <op-id>
|
||||
```
|
||||
|
||||
### Need a previous version of a commit's content
|
||||
|
||||
```bash
|
||||
jj evolog -r <change-id> -p # Find the version you want
|
||||
jj restore --from <commit-id-from-evolog> <path> # Restore working-copy content from it
|
||||
```
|
||||
|
||||
### Restored the wrong op-id
|
||||
|
||||
```bash
|
||||
jj undo # The restore is itself a recorded op
|
||||
```
|
||||
|
||||
## Notes for agents
|
||||
|
||||
- **Always reach for `jj undo` first** when something looks wrong. Don't try to manually unwind with new commits or `jj abandon` — `undo` is the canonical safe path.
|
||||
- **The op log isn't pruned aggressively** — even a week of work is fully retrievable.
|
||||
- **`jj op restore` is recorded** — it's not destructive in the way `git reset --hard` is. You can always undo a restore.
|
||||
- **There is no stash/pop in jj** because every state is automatically a commit in the op log. Treat `jj undo` / `jj op restore` as the equivalent.
|
||||
|
||||
## Quick reference
|
||||
|
||||
| Action | Command |
|
||||
|---|---|
|
||||
| Undo last operation | `jj undo` |
|
||||
| See all operations | `jj op log` |
|
||||
| See ops with diffs | `jj op log -p` |
|
||||
| Jump to past state | `jj op restore <op-id>` |
|
||||
| Change evolution | `jj evolog -r <change-id>` |
|
||||
| Restore file from past version | `jj restore --from <commit-id> <path>` |
|
||||
@@ -0,0 +1,77 @@
|
||||
### Squashing Changes
|
||||
|
||||
`jj squash` moves changes from one revision to another. The default is `@` → its parent; pass `--into` to target any other change.
|
||||
|
||||
```bash
|
||||
# Default: squash @ into its parent
|
||||
jj squash
|
||||
|
||||
# Squash @ into a specific change (not the parent)
|
||||
jj squash --into <change-id>
|
||||
jj squash -t <change-id> # short form
|
||||
|
||||
# Squash a non-@ change into its parent
|
||||
jj squash -r <change-id>
|
||||
|
||||
# Full explicit form: any source, any destination
|
||||
jj squash --from <source-id> --into <destination-id>
|
||||
|
||||
# Squash only specific paths (the rest stay in the source)
|
||||
jj squash path/to/file.txt
|
||||
jj squash --into <change-id> src/auth/
|
||||
```
|
||||
|
||||
**Combined description prompt**: if both source and destination have non-empty descriptions, `jj squash` opens an editor to pick a combined description — and hangs in agent environments. Always pass `-m` inline when squashing two described commits together:
|
||||
|
||||
```bash
|
||||
jj squash --into <change-id> -m "feat: Combine auth changes"
|
||||
```
|
||||
|
||||
**Empty source**: when squashing leaves the source revision empty (no content vs. its parent), jj abandons it by default. Pass `--keep-emptied` to keep an empty placeholder instead.
|
||||
|
||||
**Interactive forms to avoid**: `jj squash -i` / `jj squash --interactive` open a TUI and will hang in agent environments. Use `--from` / `--into` / paths instead.
|
||||
|
||||
### Splitting Commits
|
||||
|
||||
**Warning**: `jj split` is interactive and will hang in agent environments. To divide a commit, use `jj restore` to move changes out, then create separate commits manually.
|
||||
|
||||
### Absorbing Changes
|
||||
|
||||
Automatically distribute changes to the commits that last modified those lines:
|
||||
|
||||
```bash
|
||||
# Absorb working copy changes into appropriate ancestor commits
|
||||
jj absorb
|
||||
```
|
||||
|
||||
### Abandoning Commits
|
||||
|
||||
Remove a commit entirely (descendants are rebased to its parent):
|
||||
|
||||
```bash
|
||||
jj abandon <change-id>
|
||||
```
|
||||
|
||||
### Undoing Operations
|
||||
|
||||
Reverse the last jj operation:
|
||||
|
||||
```bash
|
||||
jj undo
|
||||
```
|
||||
|
||||
This reverts the repository to its state before the previous command. Useful for recovering from mistakes like accidental `abandon`, `squash`, or `rebase`.
|
||||
|
||||
### Restoring Files
|
||||
|
||||
Discard changes to specific files or restore files from another revision:
|
||||
|
||||
```bash
|
||||
# Discard all uncommitted changes in working copy (restore from parent)
|
||||
jj restore
|
||||
|
||||
# Discard changes to specific files
|
||||
jj restore path/to/file.txt
|
||||
|
||||
# Restore files from a specific revision
|
||||
jj restore --from <change-id> path/to/file.txt
|
||||
@@ -0,0 +1,164 @@
|
||||
# Named Remotes and Multi-Remote Workflows
|
||||
|
||||
For pushing to a single remote (the common case), see `references/PUSH.md`. This file covers everything else: managing named remotes, selecting which remote to push to, tracking remote bookmarks, and the two canonical multi-remote setups.
|
||||
|
||||
## Named remotes
|
||||
|
||||
When a repo has more than one remote (e.g. `origin` = your fork, `upstream` = the canonical source), you select the target with `--remote <name>`.
|
||||
|
||||
```bash
|
||||
jj git remote list # See all remotes and their URLs
|
||||
jj git remote add upstream <url> # Add a second remote
|
||||
jj git remote rename origin fork # Rename a remote
|
||||
jj git remote set-url origin <new-url> # Change a remote's URL
|
||||
jj git remote remove old-name # Remove a remote (and forget its bookmarks)
|
||||
```
|
||||
|
||||
**Default remote selection**: when `--remote` is omitted, `jj git push` uses:
|
||||
|
||||
1. The `git.push` config setting (if set), or
|
||||
2. The remote named `origin` (if multiple remotes exist), or
|
||||
3. The single remote (if only one exists)
|
||||
|
||||
There is **no built-in option to push to multiple remotes in one command** — call `jj git push` once per remote.
|
||||
|
||||
### Pushing the same bookmark to two remotes
|
||||
|
||||
```bash
|
||||
jj bookmark move my-feature --to @ # Move the bookmark to current change
|
||||
jj git push -b my-feature --remote fork # Push to your fork
|
||||
jj git push -b my-feature --remote upstream # Push to canonical (e.g. for a PR target branch)
|
||||
```
|
||||
|
||||
### Setting a default remote
|
||||
|
||||
To avoid typing `--remote` repeatedly:
|
||||
|
||||
```bash
|
||||
# Per-repo (writes to .jj/repo/config.toml)
|
||||
jj config set --repo git.push fork
|
||||
|
||||
# Globally (writes to ~/.config/jj/config.toml)
|
||||
jj config set --user git.push origin
|
||||
```
|
||||
|
||||
### Tracking a remote bookmark
|
||||
|
||||
By default, when you `jj git fetch`, remote bookmarks appear as `<name>@<remote>` (e.g. `main@upstream`). To get a local bookmark that follows it:
|
||||
|
||||
```bash
|
||||
jj bookmark track main@upstream # Track upstream/main as a local 'main'
|
||||
jj bookmark track 'glob:release/*@upstream' # Track all upstream release branches
|
||||
```
|
||||
|
||||
Once tracked, `jj git push --tracked --remote upstream` will push all tracked bookmarks back to that remote.
|
||||
|
||||
### Fetching from a specific remote
|
||||
|
||||
```bash
|
||||
jj git fetch --remote upstream # Fetch only from upstream
|
||||
jj git fetch --all-remotes # Fetch from every configured remote
|
||||
```
|
||||
|
||||
### When a push is rejected
|
||||
|
||||
If the remote has moved since your last fetch, `jj git push` refuses (similar to `git push --force-with-lease`). Re-sync first:
|
||||
|
||||
```bash
|
||||
jj git fetch --remote <name> # Pull the remote's current state
|
||||
# (resolve any bookmark conflicts or rebase if needed)
|
||||
jj git push -b <bookmark> --remote <name> # Try again
|
||||
```
|
||||
|
||||
### Quick reference
|
||||
|
||||
| Action | Command |
|
||||
|---|---|
|
||||
| List remotes | `jj git remote list` |
|
||||
| Add a remote | `jj git remote add <name> <url>` |
|
||||
| Push to specific remote | `jj git push -b <bookmark> --remote <name>` |
|
||||
| Push all tracked bookmarks to a remote | `jj git push --tracked --remote <name>` |
|
||||
| Set default push remote (repo) | `jj config set --repo git.push <name>` |
|
||||
| Track a remote bookmark | `jj bookmark track <name>@<remote>` |
|
||||
| Fetch one remote | `jj git fetch --remote <name>` |
|
||||
| Fetch all remotes | `jj git fetch --all-remotes` |
|
||||
|
||||
## Common multi-remote workflows
|
||||
|
||||
Two canonical setups documented in [the jj docs](https://docs.jj-vcs.dev/latest/guides/multiple-remotes/). Pick the one that matches your relationship to the remotes; the config is one-time per repo.
|
||||
|
||||
**Nomenclature** (jj convention):
|
||||
- `origin` = a remote you have write access to (typically where you push)
|
||||
- `upstream` = the more canonical / well-known repo (you may not have push access)
|
||||
- Trunk is assumed to be `main`, so remote bookmarks are `main@origin` and `main@upstream`
|
||||
|
||||
### Scenario 1: GitHub-style fork contributing upstream
|
||||
|
||||
`upstream` is the canonical project; `origin` is your fork; you open PRs from `origin` against `upstream`.
|
||||
|
||||
Typical actions:
|
||||
- Fetch from `upstream` to get the latest changes
|
||||
- Push `main` to `origin` to keep your fork's `main` in sync
|
||||
- Push `my-feature` to `origin`, then open a PR targeting `upstream`
|
||||
|
||||
One-time setup:
|
||||
|
||||
```bash
|
||||
# Fetch from both remotes when you run `jj git fetch`
|
||||
jj config set --repo git.fetch '["upstream", "origin"]'
|
||||
|
||||
# Default push target is your fork
|
||||
jj config set --repo git.push origin
|
||||
|
||||
# Track both remote bookmarks named `main`
|
||||
jj bookmark track main
|
||||
|
||||
# Make upstream's main the trunk (treated as immutable; rebases stop here)
|
||||
jj config set --repo 'revset-aliases."trunk()"' main@upstream
|
||||
```
|
||||
|
||||
Why these specifically:
|
||||
- Tracking `main@upstream` keeps your local `main` updated whenever you fetch from upstream
|
||||
- Tracking `main@origin` means `jj git push` will also update your fork's `main`
|
||||
- `trunk() = main@upstream` prevents jj from rewriting commits that are already in the canonical repo
|
||||
|
||||
### Scenario 2: Independent repository, periodically integrating from upstream
|
||||
|
||||
`origin` is a long-lived repository with its own divergent history; `upstream` is the source you occasionally pull changes from but don't contribute back to.
|
||||
|
||||
Typical actions:
|
||||
- Fetch from `origin` to get the latest of your own work
|
||||
- Push bookmarks to `origin`; merge PRs into `main@origin`
|
||||
- Periodically fetch from `main@upstream` and merge/rebase/duplicate its changes into `main@origin`
|
||||
|
||||
One-time setup:
|
||||
|
||||
```bash
|
||||
# Fetch only from origin (typical case)
|
||||
jj config set --repo git.fetch '["origin"]'
|
||||
# Or fetch from both if you want upstream changes visible on every fetch:
|
||||
# jj config set --repo git.fetch '["upstream", "origin"]'
|
||||
|
||||
# Default push target is origin
|
||||
jj config set --repo git.push origin
|
||||
|
||||
# Track only origin's main — do NOT track upstream's main
|
||||
jj bookmark track main --remote=origin
|
||||
jj bookmark untrack main --remote=upstream
|
||||
|
||||
# Your origin defines the trunk (your main is the canonical line)
|
||||
jj config set --repo 'revset-aliases."trunk()"' main@origin
|
||||
```
|
||||
|
||||
Why these specifically:
|
||||
- Tracking only `main@origin` keeps `main@upstream` as a clearly separate reference you can `rebase`/`merge` from intentionally — it won't silently overwrite your local `main`
|
||||
- `trunk() = main@origin` treats your divergent line (not upstream's) as the immutable history boundary
|
||||
|
||||
### Choosing between the scenarios
|
||||
|
||||
| Question | Scenario 1 | Scenario 2 |
|
||||
|---|---|---|
|
||||
| Do you push features back to upstream as PRs? | Yes | No |
|
||||
| Should fetching from upstream update your local `main`? | Yes | No (you integrate manually) |
|
||||
| Is `upstream/main` immutable from your repo's perspective? | Yes | No (you may rewrite when integrating) |
|
||||
| Is `origin/main` allowed to diverge from `upstream/main`? | Minimally (just for syncing) | Yes (it's the point) |
|
||||
@@ -0,0 +1,84 @@
|
||||
# Token-Reducing Templates
|
||||
|
||||
Use inline `-T` templates for compact, agent-friendly jj output. Prefer inline `-T` use over editing repo or global jj config so the skill stays explicit and portable.
|
||||
|
||||
Assumptions:
|
||||
|
||||
- Assume `jj 0.41.0` or later.
|
||||
- Each template was tested with `jj 0.41.0`.
|
||||
- If a template fails to parse, treat that as jj version drift and verify with `jj <command> --help` plus `jj help -k templates`.
|
||||
- Use the commands below as written. They intentionally put `--no-pager` at the top-level `jj` invocation so agent output does not depend on pager configuration.
|
||||
|
||||
## `jj log`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager log --no-graph -n 20 -T 'change_id.shortest(8) ++ if(bookmarks, " " ++ bookmarks, "") ++ if(current_working_copy, " @", "") ++ if(empty, " (empty)", "") ++ if(conflict, " (conflict)", "") ++ " " ++ if(description, description.first_line(), "(no description)") ++ "\n"'
|
||||
```
|
||||
|
||||
This keeps the change ID, bookmark or `@`, empty/conflict markers, and the first description line. Use `shortest(8)` instead of bare `shortest()` so IDs do not collapse to one character on `jj 0.41.0`.
|
||||
|
||||
## `jj show`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager show <change-id> --stat -T 'change_id.shortest(8) ++ if(bookmarks, " " ++ bookmarks, "") ++ if(current_working_copy, " @", "") ++ if(empty, " (empty)", "") ++ if(conflict, " (conflict)", "") ++ " " ++ if(description, description.first_line(), "(no description)") ++ "\n"'
|
||||
```
|
||||
|
||||
Prefer `--stat` for a compact file summary. Swap `--stat` for `--no-patch` if you want the commit summary without any file-level diff summary.
|
||||
|
||||
## `jj diff`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager diff -T 'self.status_char() ++ " " ++ self.display_diff_path() ++ "\n"'
|
||||
```
|
||||
|
||||
Add `-r <rev>` if you want a diff for a specific revision instead of the working copy.
|
||||
|
||||
## `jj bookmark list`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager bookmark list -T 'if(self.normal_target(), self.name() ++ ": " ++ self.normal_target().change_id().shortest(8) ++ " " ++ if(self.normal_target().description(), self.normal_target().description().first_line(), "(no description)") ++ "\n", self.name() ++ ": (conflicted)\n")'
|
||||
```
|
||||
|
||||
Use this for ordinary bookmark inspection. If you are explicitly debugging conflicted bookmarks and need every old/new target, fall back to jj's default output.
|
||||
|
||||
## `jj workspace list`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager workspace list -T 'self.name() ++ ": " ++ self.target().change_id().shortest(8) ++ " " ++ if(self.target().description(), self.target().description().first_line(), "(no description)") ++ if(self.target().empty(), " (empty)", "") ++ "\n"'
|
||||
```
|
||||
|
||||
This shows workspace name, working-copy change ID, description, and whether that working copy is empty.
|
||||
|
||||
## `jj op log`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager op log --no-graph -n 20 -T 'id.short(8) ++ " " ++ time.start().ago() ++ " " ++ description.first_line() ++ "\n"'
|
||||
```
|
||||
|
||||
Use this first when you need recovery context but do not yet need full diffs. Add `-p` only after you have narrowed down the interesting op IDs.
|
||||
|
||||
## `jj evolog`
|
||||
|
||||
Tested with: `jj 0.41.0`
|
||||
|
||||
```bash
|
||||
jj --no-pager evolog -r <change-id> --no-graph -n 20 -T 'commit.change_id().shortest(8) ++ " " ++ if(commit.description(), commit.description().first_line(), "(no description)") ++ " | " ++ operation.id().short(8) ++ " " ++ operation.description().first_line() ++ "\n"'
|
||||
```
|
||||
|
||||
This keeps the evolving change summary on the left and the rewriting operation on the right.
|
||||
|
||||
## Not Templated
|
||||
|
||||
`jj st` and `jj status` do not expose a template flag in `jj 0.41.0`, so leave status output untemplated. The same applies to commands like `jj undo`, `jj op restore`, and `jj resolve` where the value is in the side effect, not in custom rendering.
|
||||
@@ -0,0 +1,209 @@
|
||||
# Parallel Workspaces
|
||||
|
||||
Use `jj workspace` when multiple agents need independent working copies of the same repo. Each workspace gets its own `@` while sharing the same repo store and operation log.
|
||||
|
||||
**Tested with jj 0.41.0**
|
||||
|
||||
This skill intentionally prefers project-local workspace directories when they are safely ignored. Directory priority for this skill:
|
||||
|
||||
1. `.workspaces/`
|
||||
2. `workspaces/`
|
||||
3. Repo-local instructions such as `AGENTS.md` or `CLAUDE.md`
|
||||
4. Ask the user
|
||||
|
||||
Do not replace this with a blanket "sibling directories only" rule.
|
||||
|
||||
## Before Creating a Workspace
|
||||
|
||||
First, make sure project-local workspaces will not leak into Git history:
|
||||
|
||||
```bash
|
||||
grep -E '^\.?workspaces/?$' .gitignore 2>/dev/null
|
||||
```
|
||||
|
||||
If the entry is missing, add it before `jj workspace add` and record that change using the normal workflow from `references/NEW_CHANGE.md`:
|
||||
|
||||
```bash
|
||||
echo ".workspaces/" >> .gitignore
|
||||
```
|
||||
|
||||
Never skip this check. `jj workspace add` creates directories that contain `.jj/` metadata, and the outer Git repo must ignore them.
|
||||
|
||||
Use descriptive names so `jj workspace list` and `jj log` stay readable:
|
||||
|
||||
```bash
|
||||
REPO_NAME=$(basename "$(jj workspace root)")
|
||||
WORKSPACE_PATH=".workspaces/${REPO_NAME}-<purpose>"
|
||||
```
|
||||
|
||||
Examples:
|
||||
|
||||
- `.workspaces/myrepo-test-runner`
|
||||
- `.workspaces/myrepo-reviewer-agent`
|
||||
- `.workspaces/myrepo-refactor-experiment`
|
||||
|
||||
Avoid generic names such as `tmp`, `wip`, or `new`.
|
||||
|
||||
## Creating and Bootstrapping
|
||||
|
||||
Create the workspace and move into it:
|
||||
|
||||
```bash
|
||||
jj workspace add "$WORKSPACE_PATH"
|
||||
cd "$WORKSPACE_PATH"
|
||||
```
|
||||
|
||||
After creation:
|
||||
|
||||
- the workspace has its own working-copy commit
|
||||
- it appears in log output as `<workspace-name>@`
|
||||
- it shares history and the operation log with the main workspace
|
||||
- snapshots in this workspace affect only this workspace's `@`
|
||||
|
||||
If the repo needs environment setup, bootstrap it in the new workspace before handing it to another agent:
|
||||
|
||||
| Marker file | Setup command |
|
||||
| --- | --- |
|
||||
| `package.json` | `npm install` |
|
||||
| `Cargo.toml` | `cargo build` |
|
||||
| `pyproject.toml` | `uv sync` |
|
||||
| `Gemfile` | `bundle install` |
|
||||
| `flake.nix` | `nix develop` |
|
||||
| `go.mod` | `go mod download` |
|
||||
| `mix.exs` | `mix deps.get` |
|
||||
|
||||
## Agent Handoff
|
||||
|
||||
When one agent creates a workspace for another, always report:
|
||||
|
||||
- the absolute workspace path
|
||||
- the change ID the agent should edit
|
||||
- the exact `cd` command
|
||||
- the exact `jj edit <change-id>` command
|
||||
- the scope boundaries
|
||||
|
||||
Use a handoff like this:
|
||||
|
||||
```text
|
||||
Workspace: /absolute/path/to/.workspaces/myrepo-tests
|
||||
Change ID: abcdefgh
|
||||
|
||||
cd /absolute/path/to/.workspaces/myrepo-tests
|
||||
jj edit abcdefgh
|
||||
|
||||
Rules:
|
||||
- Always use -m for messages.
|
||||
- Run jj st after every mutation.
|
||||
- Do not modify files outside the assigned scope.
|
||||
```
|
||||
|
||||
Absolute paths matter. Agents lose track of relative locations more often than they lose track of change IDs.
|
||||
|
||||
## Monitoring Progress
|
||||
|
||||
Start from the compact `jj log` command in `references/TEMPLATES.md`, then swap in the revset you need:
|
||||
|
||||
- all workspace tips: `-r 'working_copies()'`
|
||||
- one named workspace: `-r '<workspace>@'`
|
||||
|
||||
Examples of the revsets themselves:
|
||||
|
||||
```bash
|
||||
working_copies()
|
||||
reviewer@
|
||||
```
|
||||
|
||||
See `references/QUERY_LANGUAGES.md` for the revset syntax behind those examples.
|
||||
|
||||
## Combining Results
|
||||
|
||||
When a workspace finishes its work, bring that change back to the main line and retire the workspace. Do not decide silently; ask the user which strategy they want.
|
||||
|
||||
### Strategy 1: Rebase into the Default Workspace
|
||||
|
||||
Use this when one developer is orchestrating multiple agents and the result should land as ordinary commits in the default workspace.
|
||||
|
||||
```bash
|
||||
jj rebase -s <workspace-change-id> -d @
|
||||
jj workspace forget <workspace-name>
|
||||
rm -rf "$WORKSPACE_PATH"
|
||||
```
|
||||
|
||||
If the repo uses bookmarks for shipping work, move or create the bookmark after the rebase using the normal push workflow from `references/PUSH.md`.
|
||||
|
||||
### Strategy 2: Keep an Explicit Merge
|
||||
|
||||
Use this when both lines of work are independently meaningful and the merge structure should remain visible:
|
||||
|
||||
```bash
|
||||
jj new <change-from-workspace-a> <change-from-workspace-b> -m "merge: combine parallel work"
|
||||
```
|
||||
|
||||
### Strategy 3: Push a Bookmark and Open a PR
|
||||
|
||||
Use this when the work needs human review before landing:
|
||||
|
||||
```bash
|
||||
jj bookmark create my-feature -r <workspace-change-id>
|
||||
jj git push -b my-feature
|
||||
```
|
||||
|
||||
Decision guide:
|
||||
|
||||
| Situation | Default suggestion |
|
||||
| --- | --- |
|
||||
| Solo developer running multiple local agents | Strategy 1 |
|
||||
| Long-lived feature with checkpoints | Strategy 1, then push a bookmark when ready |
|
||||
| Human review required | Strategy 3 |
|
||||
| Both lines of work are independently meaningful | Strategy 2 |
|
||||
|
||||
If the context is ambiguous, suggest Strategy 1 first and ask whether the user wants the result to land in the default workspace or as a PR.
|
||||
|
||||
## Listing and Cleaning Up
|
||||
|
||||
```bash
|
||||
jj workspace list
|
||||
jj workspace forget <workspace-name>
|
||||
rm -rf "$WORKSPACE_PATH"
|
||||
```
|
||||
|
||||
If you need to inspect `jj workspace list` output as an agent, use the compact command from `references/TEMPLATES.md`.
|
||||
|
||||
`jj workspace forget` only unregisters the workspace. It does not delete files from disk.
|
||||
|
||||
## `update-stale`
|
||||
|
||||
If another workspace rewrites the commit your workspace had checked out, jj marks that workspace as stale. Use this first:
|
||||
|
||||
```bash
|
||||
jj workspace update-stale
|
||||
jj st
|
||||
```
|
||||
|
||||
Do not improvise a manual repair before trying `update-stale`. If the old operation is gone, jj can create a recovery commit with the current working-copy contents instead of silently discarding them.
|
||||
|
||||
## Conflict Avoidance
|
||||
|
||||
| Risk | Recommended mitigation |
|
||||
| --- | --- |
|
||||
| Build outputs or generated files | Ignore them or give each workspace separate output paths |
|
||||
| Shared config files | Assign a single owner for that file or change it serially |
|
||||
| Lockfiles / dependency updates | Let one task own dependency changes |
|
||||
| Same source files across workspaces | Redesign the task boundary or serialize the work |
|
||||
|
||||
## Critical Rules
|
||||
|
||||
1. Never skip the `.gitignore` check for project-local workspace directories.
|
||||
2. Always follow the directory priority: `.workspaces/` -> `workspaces/` -> repo instructions -> ask.
|
||||
3. Use descriptive names: `${REPO_NAME}-<purpose>`, not `tmp`.
|
||||
4. Bootstrap the workspace before handing it to another agent.
|
||||
5. Report the absolute path, change ID, and next commands when a workspace is ready.
|
||||
6. Run `jj workspace forget` before deleting the directory.
|
||||
7. Ask before choosing between rebase, merge, or PR integration.
|
||||
8. Use `jj workspace update-stale` as the first response to a stale workspace.
|
||||
|
||||
## Reference
|
||||
|
||||
Convention adapted from [edmundmiller/dotfiles `using-jj-workspaces`](https://lobehub.com/skills/edmundmiller-dotfiles-using-jj-workspaces).
|
||||
|
||||
Additional handoff, monitoring, stale-workspace, and conflict-avoidance patterns were adapted from [joshuadavidthomas/agent-skills `jj`](https://github.com/joshuadavidthomas/agent-skills/tree/main/jj) and its [`workspaces.md`](https://raw.githubusercontent.com/joshuadavidthomas/agent-skills/main/jj/workspaces.md), while intentionally preserving this skill's local `.workspaces/` / `workspaces/` directory priority and local change-creation workflow.
|
||||
Reference in new issue
Block a user