Update skills from recent usage
jj: rewrite for v0.39 (bookmark advance, op revert, commit
workflow, trimmed redundant sections). jj-workspaces: relative
paths note, cleanup after rebase. working-in-the-open: stronger
default-silence guidance. self-improving-skills: lean-start and
no-bulk-copy rules. ranger and zoekt: new learned patterns.
Assisted-by: Claude Opus 4.6 via pi
diff --git a/ai/AI.md b/ai/AI.md
index 7981fa22..b83a4047 100644
--- a/ai/AI.md
+++ b/ai/AI.md
@@ -13,7 +13,7 @@ Rules:
- Don't offer unsolicited suggestions, but ask when information is missing to avoid guessing
- End responses after delivering requested information
- Reference specific user content, not generic praise
-- Avoid broad adjectives (great, brilliant, amazing) without substantive basis
+- Avoid broad adjectives (great, brilliant, amazing, clean) without substantive basis
- Prioritize cognitive clarity over social comfort
- When working with GitHub, read .github templates for PRs and issues
- Attribute AI-written content when possible (Co-Authored-By, footer, or similar)
diff --git a/ai/claude/skills/jj-workspaces/SKILL.md b/ai/claude/skills/jj-workspaces/SKILL.md
index 1c768edc..5c9e8d05 100644
--- a/ai/claude/skills/jj-workspaces/SKILL.md
+++ b/ai/claude/skills/jj-workspaces/SKILL.md
@@ -14,6 +14,8 @@ Create isolated jj workspaces for experimentation, parallel development, and sub
**Important:** Run `jj` (or `jj status`) periodically in each workspace. jj only snapshots the working copy when you run a command—it doesn't watch for file changes. Running `jj` ensures it sees your edits.
+**Note (v0.39+):** `jj workspace add` now links with relative paths by default, enabling workspaces to work inside containers or when moved together. Existing workspaces with absolute paths continue to work.
+
## When to Use
**Triggers:**
@@ -64,6 +66,9 @@ cd work/<name>
**If successful:** Merge back:
```bash
jj rebase -s <name>@ -d @
+jj workspace forget <name>
+jj abandon 'empty() & description(exact:"") & @-'
+rm -rf work/<name>
```
**If unsuccessful:** Forget and clean up:
@@ -169,6 +174,7 @@ jj workspace update-stale
| Skipping `jj workspace update-stale` | Run in main workspace after workspace operations |
| Creating workspaces during dispatch | Create ALL workspaces BEFORE dispatch |
| Agent touching other workspaces | Agents work ONLY in assigned path |
+| Empty WC commits after rebase | After rebase + forget, run `jj abandon 'empty() & description(exact:"") & @-'` to drop the workspace's leftover empty WC |
| Forgetting cleanup | Remove directories after forgetting workspace |
| jj not seeing file changes | Run `jj` or `jj status` periodically—jj only snapshots on command execution |
diff --git a/ai/claude/skills/jj/SKILL.md b/ai/claude/skills/jj/SKILL.md
index a741257e..f1aa5743 100644
--- a/ai/claude/skills/jj/SKILL.md
+++ b/ai/claude/skills/jj/SKILL.md
@@ -7,154 +7,101 @@ description: Use when needing jj command reference, syntax, or behavior - direct
Use `jj --help` for authoritative command reference and current flags.
-## Quick Start
-
-Run `jj <command> --help` for detailed command documentation:
-
-```bash
-jj --help # Full command list
-jj status --help # Specific command details
-jj log --help # Syntax and options
-```
-
## Core Workflow
1. Make file edits (changes exist in working copy)
-2. `jj describe <message>` (write commit message)
-3. `jj new` (create next commit, working copy becomes immutable)
-4. Repeat
+2. `jj commit -m 'message'` (snapshot current changes, start new empty working copy)
+3. Repeat
+
+Use `jj describe` to rewrite a commit message, `jj new <rev>` to start
+working on top of a revision.
## Key Differences from Git
-No staging area: working copy changes map directly to commits. Operations are immutable: `jj new`, `jj squash`, `jj rebase` create new commits rather than modify existing ones. Conflicts are queryable through `jj status` and `jj log`. The operation log (`jj op log`) shows all operations for undo/recovery.
+No staging area: working copy changes map directly to commits. Operations
+are immutable: `jj new`, `jj squash`, `jj rebase` create new commits rather
+than modify existing ones. The operation log (`jj op log`) enables undo/recovery.
-## Bookmarks (Named References)
+## Bookmarks and Pushing
-In jj, **bookmarks** are named references to commits, similar to git branches. Create and manage them:
+Bookmarks are mutable named pointers to commits (like git branches).
+Use `jj new <bookmark>` to start working on top of one.
```bash
-jj bookmark create feature-auth -r main # Create bookmark from main
-jj bookmark list # Show all bookmarks
-jj bookmark list -r feature-auth # Show specific bookmark
-jj bookmark delete feature-auth # Delete bookmark
-jj checkout feature-auth # Switch to bookmark
-jj bookmark set feature-auth -r <rev> # Move bookmark to different commit
+jj bookmark list # show all bookmarks
+jj bookmark set feature -r <rev> # move bookmark to revision
+jj bookmark track main --remote=origin # start tracking a remote bookmark
```
-**Key differences from git branches:**
-- Bookmarks are immutable references (can't be modified in place)
-- Multiple bookmarks can point to same commit
-- `jj checkout` switches working copy to bookmark; use `jj new` to create commits on that bookmark
+### Advancing bookmarks after commit
-**Use bookmarks for:** Feature branches, parallel work, named release points. NOT for temporary work (use detached state instead).
-
-## Pushing to Remote
+`jj bookmark advance` moves the nearest ancestor bookmark(s) forward to a
+target revision — the preferred way to move `main` after committing on top
+of it.
```bash
-# Push existing tracked bookmarks
-jj git push -b <bookmark-name>
+jj bookmark advance # advance closest bookmarks to @ (default)
+jj bookmark advance --to @- # advance closest bookmarks to @-
+jj bookmark advance main --to @- # advance specific bookmark
+```
-# Create and push new bookmark in one step (preferred for PRs)
-jj git push --named <bookmark-name>=<revision>
+After `jj commit`, the working copy `@` is empty so `jj bookmark advance`
+with no args works — the bookmark is an ancestor of `@`.
-# Push all bookmarks including new ones
-jj git push --all
-```
+### Pushing
-**Note:** `--named` creates the bookmark, pushes it, and auto-tracks it. Use this for PRs.
+```bash
+jj git push -b <bookmark> # push tracked bookmark
+jj git push -c <rev> # create auto-named bookmark and push
+jj git push --named <name>=<rev> # create named bookmark and push
+```
-**`-b` / `--bookmark` refuses to push untracked (local-only) bookmarks.** If a
-bookmark exists locally but has never been pushed, `-b` will error with
-"Refusing to create new remote bookmark". Use `--named` instead to push and
-auto-track it in one step. Use `-b` only for bookmarks that are already tracked
-(previously pushed or fetched).
+`-b` refuses to push untracked bookmarks ("Refusing to create new remote
+bookmark"). Use `--named` to create, push, and auto-track in one step.
+`-c` generates a bookmark name from the change ID (`push-<short-change-id>`).
## Restoring Files
-`jj restore` does **not** have `-r`/`--revision`. It uses `--from` (source)
-and `--into`/`--to` (destination):
+`jj restore` uses `--from` and `--into`/`--to`, not `-r`:
```bash
-jj restore --from kn --into kn gdev-genie/Cargo.lock # restore one file in a revision from its parent
-jj restore --changes-in @ # undo all changes in working copy (like jj abandon but keeps metadata)
-jj restore gdev-genie/Cargo.lock # restore file in working copy from parent
+jj restore --changes-in @ # undo all working copy changes
+jj restore SOME_FILE # restore file from parent
+jj restore --from kn --into kn FILE # restore file in a specific revision
```
-`--changes-in <REVSET>` undoes changes in a revision compared to its
-parents — equivalent to `--into REVSET --from REVSET-` for single-parent
-revisions.
-
## Common Pitfalls
**Quote revsets containing parentheses.** Bash interprets `()` as subshell
-syntax. Always quote revsets like `trunk()`:
+syntax:
```bash
jj log -r 'trunk()' # correct
-jj diff --from 'trunk()' --to @ # correct
jj log -r trunk() # WRONG — bash syntax error
```
-**`jj show` does not accept path arguments.** Unlike `git show`, you cannot
-write `jj show @- -- path/to/file`. Use `jj diff` instead:
+**`jj show` does not accept path arguments.** It takes an optional revision
+but cannot be scoped to a path. Use `jj diff` instead:
```bash
jj diff -r @- # all changes in parent revision
jj diff -r @- path/to/file # specific file in parent revision
-jj diff --from @-- --to @- some/dir # between two revisions, scoped to path
-```
-
-**Path filtering uses positional fileset args, not revset syntax.** To find
-revisions that touched a path, pass the path as a positional argument:
-
-```bash
-jj log ai/src/main.rs # revisions touching this file
-jj log -r '::@' ai/src/ # scoped to ancestors of @
```
-**Fileset expressions with special characters need quoting.** Filenames
-containing commas, parentheses, or other meta characters must be quoted
-inside `glob:` patterns. Use `glob:"pattern"` with the pattern in double
-quotes:
+**Fileset expressions with special characters need quoting.** Use
+`glob:"pattern"` with the pattern in double quotes:
```bash
-jj diff -- 'glob:"bin/*" ~ glob:"bin/,special"' # exclude a file with comma
-jj commit -m 'msg' -- 'glob:"bin/*" ~ glob:"bin/,clean-url"'
+jj diff -- 'glob:"bin/*" ~ glob:"bin/,special"'
```
-Without quotes around the pattern, characters like `,` are parsed as fileset
-syntax and cause errors. Plain paths without meta characters don't need inner
-quotes: `bin/de-utm` is fine as-is.
+**`jj op undo` has been removed (v0.39+).** Use `jj op revert` or
+`jj undo`/`jj redo`.
-**Inherited conflicts are baked into the commit.** If a revision inherits a
-conflict from its parent, `jj restore --from parent --into child` won't help
-because the child doesn't introduce the conflict itself (`jj diff -r child`
-shows nothing for that file). Check with `jj resolve --list -r <rev>` and
-`jj log -r '<rev> | parents(<rev>)'` to see where the conflict originates.
-To drop an inherited conflict, rebase the revision onto a non-conflicted
-ancestor — but only if the revision's own changes don't depend on the
-conflicted parent's work.
-
-## Command Categories
-
-Run `jj --help` to see all commands. Main categories:
-
-Repository: init, clone, status
-Changes: new, describe, commit, edit
-History: log, show, diff
-Modification: squash, split, rebase
-Bookmarks: bookmark create/list/delete
-Sync: git fetch, git push
-Conflict: resolve
-Recovery: undo, op log, op undo
+**Put `-m` before `--` or fileset args.** jj parses everything after `--` as
+fileset, so `-m` placed after `--` becomes a parse error.
## When to Use jj --help
-Direct command help is always more current than documentation. Use it for:
-
-- Exact flag names and syntax
-- Current command options
-- Command behavior details
-- Examples and edge cases
-
-Never rely on this skill's command list as authoritative. Always run `jj <command> --help` to verify behavior, flags, and current options.
+Never rely on this skill as authoritative. Always run `jj <command> --help`
+to verify behavior, flags, and current options.
diff --git a/ai/claude/skills/ranger/SKILL.md b/ai/claude/skills/ranger/SKILL.md
new file mode 100644
index 00000000..28b95be3
--- /dev/null
+++ b/ai/claude/skills/ranger/SKILL.md
@@ -0,0 +1,52 @@
+---
+name: ranger
+description: Use when managing tasks with the ranger CLI — creating backlogs, tracking work, picking up tasks, prioritizing, or following the ranger PM workflow in any project
+---
+
+# Ranger — Task Management
+
+Use the `ranger` CLI to manage project tasks. Run `ranger --help` for commands and syntax.
+
+All work must correspond to a task in the backlog. If the user asks for something that isn't tracked, create a task first, then pick it up. When the user says "let's keep working" without specifying a task, pick up the next queued task (top of the queue).
+
+## Quick Reference
+
+Commands use `ranger <noun> <verb>` structure. Top-level nouns: `backlog` (alias `b`), `task` (alias `t`), `comment` (alias `c`), `tag`, `blocker`.
+
+```bash
+# Backlogs
+ranger backlog list # List all backlogs
+
+# Tasks
+ranger task create --backlog <name> "Title" # Create a task
+ranger task create --backlog <name> --state queued --description "..." "Title"
+ranger task list --backlog <name> # List tasks
+ranger task show <key> # Show task details
+ranger task edit <key> --state <state> # Change task state
+ranger task move <key> -B <other> # Reorder: place before another task
+ranger task move <key> -A <other> # Reorder: place after another task
+ranger task delete <key> # Delete a task
+```
+
+Task states for `--state`: `icebox`, `queued`, `in_progress`, `done`.
+
+The `RANGER_DEFAULT_BACKLOG` env var sets the default `--backlog` value so you can omit it.
+
+Task keys are short prefixes (e.g. `tl`) of longer IDs — use just enough to be unique. There is no `--top` or `--bottom` flag; to move to the top, use `-B` with the first task's key.
+
+## Conventions
+
+- **Icebox**: ideas, not committed to
+- **Queued**: committed, ordered by priority (top = most important)
+- **In Progress**: actively being worked on
+- **Done**: finished
+
+Top of the queue = most important. Bias toward quick wins — small easy tasks should be prioritized higher by default.
+
+## Workflow
+
+- Don't mark a task **done** until the changes are committed. Commit first, then transition.
+
+---
+
+*This is a self-improving skill — see the `self-improving-skills` skill.*
diff --git a/ai/claude/skills/self-improving-skills/SKILL.md b/ai/claude/skills/self-improving-skills/SKILL.md
index 89fba72b..b76d83d3 100644
--- a/ai/claude/skills/self-improving-skills/SKILL.md
+++ b/ai/claude/skills/self-improving-skills/SKILL.md
@@ -36,11 +36,24 @@ Once you've figured it out, that's exactly the kind of thing to capture in the s
- Common mistakes and fixes
- Workflows you followed
- Gotchas and edge cases
-3. **Keep the structure clean.** Follow the section pattern from existing content, or start with:
+3. **Keep additions small.** Add exactly the missing piece — a command, a gotcha, a workflow step. Don't bulk-import documentation from `--help` or reference material. The skill captures what you *learned through use*, not what you *could look up*.
+4. **Keep the structure clean.** Follow the section pattern from existing content, or start with:
- Quick Reference (commands/syntax)
- Common Workflows
- Common Mistakes
-4. **Don't add speculative content.** Only document what you actually used and verified this session.
+5. **Don't add speculative content.** Only document what you actually used and verified this session.
+
+## Mark Self-Improving Skills
+
+When creating a self-improving skill, note it in the skill itself so future sessions know to apply this workflow. Add a line like:
+
+> *This is a self-improving skill — see the `self-improving-skills` skill.*
+
+This closes the loop: the skill gets loaded, the agent sees the note, loads this skill, and knows to update after use.
+
+## New Skills Should Start Lean
+
+When creating a new self-improving skill, resist the urge to front-load it with everything you know. Start with just enough to orient — what the tool is, the core workflow rule, key conventions. Everything else gets discovered through use and added incrementally. A skill that starts comprehensive has nowhere to grow and no guarantee its content reflects real usage.
## What NOT to Do
@@ -48,3 +61,5 @@ Once you've figured it out, that's exactly the kind of thing to capture in the s
- Don't add content you didn't verify during this session
- Don't remove existing content that's still accurate
- Don't bloat the skill with edge cases nobody's hit yet
+- Don't restructure or rewrite surrounding sections — add exactly the missing piece and leave the rest alone
+- Don't bulk-copy from `--help` output, READMEs, or other reference material — the skill is a journal of learned experience, not a mirror of existing docs
diff --git a/ai/claude/skills/working-in-the-open/SKILL.md b/ai/claude/skills/working-in-the-open/SKILL.md
index e3817bec..4c467711 100644
--- a/ai/claude/skills/working-in-the-open/SKILL.md
+++ b/ai/claude/skills/working-in-the-open/SKILL.md
@@ -15,16 +15,22 @@ Document the reasoning behind code changes as you work. The diff shows *what* ch
## Default: Don't Comment
-**Most work does not need a comment.** The commit message is the record. Only comment when you have context the commit cannot capture — a decision between alternatives, a blocker that changed scope, or a summary the user explicitly asked for.
+**The overwhelming default is silence.** Do not comment. Do not even consider commenting. The commit message is the record.
-Before even considering a comment, ask: "Does this say something the commit doesn't?" If no, skip it entirely — don't draft it, don't propose it, don't ask the user about it.
+The only justification for a comment is context the commit *cannot* capture — a decision between alternatives, a blocker that changed scope, or a summary the user explicitly asked for. That's it. Three cases. Everything else is noise.
+
+**Never narrate your own process.** "Starting work", "reviewing the schema", "planning the approach" — these are not useful to anyone reading the issue later. They are filler. Do not post them.
+
+Before writing a comment, pass this test: "Would a teammate reading this issue six months from now learn something they couldn't get from the commits or PR?" If the answer isn't a clear yes, don't comment.
### Specifically, Do NOT Comment When
+- **You're announcing you're starting work.** The state change (→ in_progress) already signals that. Never narrate "picking up this task" or "beginning investigation."
+- **You're describing what you're about to do.** Plans belong in your head, not in issue comments. The work itself is the record.
- **Work is complete and a PR is being opened.** The PR links to the issue and serves as the summary.
- **The comment would restate the commit message.** Even partially. "Switched X to Y, updated CI" after a commit that says exactly that is pure noise — regardless of whether it's phrased differently.
-- **You're announcing you're starting work.** The state change (→ in_progress) already signals that.
- **The work was straightforward.** If there were no surprises, no alternatives considered, no scope changes — there's nothing to document beyond the commit.
+- **You feel like you should say *something*.** That impulse is wrong. Resist it.
## The Three Milestones
diff --git a/ai/claude/skills/zoekt/SKILL.md b/ai/claude/skills/zoekt/SKILL.md
index 33ae851b..b32302a7 100644
--- a/ai/claude/skills/zoekt/SKILL.md
+++ b/ai/claude/skills/zoekt/SKILL.md
@@ -15,6 +15,18 @@ skill starts sparse and grows through use — follow the
self-improving-skills guidelines when you learn something worth
capturing.
+## Indexing
+
+```bash
+# Git repo — -index is required or shards go nowhere useful
+zoekt-git-index -index ~/.zoekt /path/to/repo
+
+# Non-git directory
+zoekt-index -index ~/.zoekt /path/to/dir
+```
+
+Index shards land in `~/.zoekt/` — the same default `zoekt` searches.
+
## Keeping the index fresh
Before searching, check whether the current repo has a usable index.
@@ -25,9 +37,7 @@ doesn't block the current task.
2. If the index is missing or older than the most recent change,
reindex in the background. Use `zoekt-git-index` in a git repo or
`zoekt-index` for non-git directories.
-3. Run `--help` on whichever indexer you need to find the right
- invocation.
-4. While the index builds, fall back to grep/ripgrep for the immediate
+3. While the index builds, fall back to grep/ripgrep for the immediate
search. Switch to zoekt once the background task completes.
Don't wait on indexing. The point is to have the index ready for