# renri

`renri` (連理) is a single CLI for managing both **git worktrees** and
**jj workspaces**. It auto-detects the backend, dispatches to the right
one, and exposes one verb set across both.

## When to use proactively

**Without being asked**, prefer creating a renri worktree for any of:

- **Reviewer feedback on an open PR** — branch off the PR branch in a
  worktree, push fixes, leave main untouched.
- **A multi-commit feature or refactor** that will land as a single PR.
- **Risky or experimental changes** you might want to throw away or
  compare against main.
- **Parallel agent sessions** on the same repo — one agent on feature
  A, another on feature B, no shared working tree to fight over.

**Skip renri for**:

- Trivial typo / whitespace / docs-wording fixes.
- Single-file config bumps (Cargo.toml version, dependency upgrade).
- Anything you would do directly on main without a PR.

The cost of a worktree is one `renri add` + one `cd`; the benefit is
that main stays clean and the work is named, parkable, and discardable.

## When the user explicitly asks

Use this skill when the user wants to:

- Create / list / switch / remove worktrees in a parallel-development
  workflow (typical AI-coding pattern: one worktree per agent session).
- Spin up isolated working copies for jj workspaces, including the
  colocated git+jj case.
- Share base config across machines via `include = [...]` / per-host
  / per-OS Tera conditionals.
- Clean up stale worktrees / forgotten jj workspaces.

## Standard workflow for PR-style work

```sh
# 1. Create a worktree on a fresh branch
renri add fix/review-feedback

# 2. Move there (cd-wrapper from `renri shell-init` makes this work)
renri cd fix/review-feedback

# 3. Make the changes, commit, push
# ... edit / cargo test / git commit / git push -u origin fix/review-feedback

# 4. Open a PR (or push fixes to an existing PR branch)

# 5. After merge, clean up
renri remove fix/review-feedback   # or: renri prune (after main pulls)
```

## Verbs

- `renri init [--force]` — write a starter `renri.toml` in the
  current directory. The template is heavily commented; uncomment
  what's needed.
- `renri add <name>` — create a new worktree (git) or workspace (jj).
  For git, `<name>` becomes a new branch off HEAD; for jj, a bookmark
  attached to the new workspace's working-copy commit. If `<name>`
  matches an existing branch / bookmark, attaches to it instead.
  **If `<name>` is omitted**, prompts interactively unless
  `--non-interactive` is set.
- `renri list` (alias `ls`) — show all worktrees with name, path,
  branch, and flags.
- `renri cd <name>` — print the absolute path of a worktree on stdout.
  Designed to be wrapped: `cd "$(renri cd foo)"`. The shell wrapper
  generated by `renri shell-init <bash|zsh|fish|powershell>` does this
  automatically. **If `<name>` is omitted**, opens a fuzzy picker.
- `renri remove <name>` (alias `rm`) — remove a worktree (git) or
  forget a workspace (jj) and delete its directory. Refuses to
  remove the main worktree. Runs configured `pre_remove` hooks first.
  **If `<name>` is omitted**, opens a fuzzy picker.
- `renri exec <name> -- <command...>` — run a command inside the
  named worktree, streaming stdio. **If `<name>` is omitted**, opens
  a fuzzy picker.
- `renri prune` — clean up stale entries: for git, removes worktree
  metadata for deleted directories; for jj, forgets workspaces whose
  root path is gone (the missing `jj workspace prune` analog).
- `renri config show` — print the resolved configuration, the
  computed worktree path for the current branch, and the list of
  config sources.
- `renri shell-init <bash|zsh|fish|powershell>` — emit a shell snippet
  that makes `renri cd` actually change the parent shell's directory.

## Global flags

- `--vcs git|jj` — force a backend instead of auto-detecting.
  Auto-detection picks jj for colocated repos.
- `--non-interactive` — disable the interactive picker fallback. Use
  in scripts and CI; missing required arguments become errors.

## Configuration

Config lives at `<repo>/renri.toml` and (optionally)
`<config_dir>/renri/config.toml`, both loaded via the
[teravars](https://github.com/yukimemi/teravars) library so they
support:

- `include = ["base.toml"]` — pull in another config file.
- `{% if system.os == "windows" %}` / `{% if system.host == "..." %}` —
  per-OS / per-host overrides via Tera control flow.
- `{{ env(name='HOME') }}`, `{{ system.cwd }}`, etc. — standard
  helpers from teravars.

Layout templates have access to `vcs.{owner, repo, branch, host}`
which renri populates from the origin remote and the working-copy
state at use time.

Hooks are typed: `type = "copy" | "symlink" | "command"`.

## Common workflows

**Spinning up a worktree for an agent session:**

```sh
renri add feature/auth
renri cd feature/auth        # with shell-init wrapper, this cds
# now run your agent CLI in the new worktree
```

**Per-host worktree root** (laptop vs desktop):

```toml
# renri.toml
[layout]
{% if system.host == "thinkpad" %}
worktree_root = "/home/yuki/wt"
{% elif system.os == "windows" %}
worktree_root = "C:/wt"
{% else %}
worktree_root = "{{ env(name='HOME') }}/wt"
{% endif %}
```

**Cleaning up after `rm -rf`-ing worktree directories:**

```sh
renri prune
```

**Per-worktree dev-server ports (no more `:3000` collisions):**

```toml
# renri.toml
[layout]
worktree_root = "{{ env(name='HOME') }}/wt"

[[hooks.post_create]]
type = "command"
run = "echo PORT={{ vcs.branch | hash | port_offset(start=3000, range=1000) }} > .env.local"
```

`hash` and `port_offset` are teravars Tera filters. The pipeline
turns each branch name into a deterministic port in `[3000, 4000)`,
so three concurrent worktrees of the same project never fight for
the same port.

## Install renri itself

The skill describes how to use `renri`; you still need the binary on
your PATH:

```sh
cargo install renri
# or pre-built binaries from https://github.com/yukimemi/renri/releases
```

For full reference, see <https://github.com/yukimemi/renri>.
