···11-{"id":"is-tree-scan-priority","title":"Prioritized directory scanning: stream recently-changed projects first","description":"Currently is-tree processes directories in filesystem order and sorts after all results are collected. For large directory trees, this means waiting for the full scan before seeing the most relevant results.\n\nThis ticket tracks adding **scan priority** — deciding which directories to process first based on cheap heuristics, so the most interesting projects stream to screen immediately.\n\nKey aspects:\n\n1. **Pre-scan heuristics** — Use cheap filesystem metadata (mtime of the directory itself, presence of recent changes) to order the work queue before the heavier detection/formatting runs. `change-date` (file mtime) is essentially free from `stat` and correlates well with \"what am I working on.\"\n\n2. **Streaming output** — Emit results as each directory is processed, in priority order, rather than buffering everything. Combined with pre-scan ordering, the user sees their most-recently-worked-on projects first.\n\n3. **Atuin session priority** — Integrate with atuin session data (see is-tree-atuin-session-tracking) to boost directories associated with active sessions to the top of the scan queue.\n\n4. **Pre-filtering** — Allow filtering the scan set before processing (e.g. only scan directories modified in the last N days, or only directories with active sessions). This reduces total work for large trees.\n\n5. **New sort columns** — Add any additional sortable columns needed to support priority-aware output (e.g. session recency, directory mtime as a first-class column).","acceptance_criteria":"- Add `--scan` mode that performs lightweight discovery/classification only (`git`, `jj`, `worktree-git`, `worktree-jj`) without resolving expensive inspection columns.\n- `--scan` output streams line-by-line as candidates are found; users see early results before the full scan completes.\n- Default `--scan` output is one directory path per line (pipeline-safe), suitable for pickers and downstream commands.\n- Scan priority ordering still applies (recently changed first by default), and pre-filtering can reduce scan set.\n- Selected paths can flow back into deep inspection through stdin (`is-tree --scan | ... | is-tree --stdin --format all`, or equivalent auto-detected piped stdin behavior).\n- Existing non-scan behavior and explicit `--sort` post-processing remain compatible.","status":"open","priority":1,"issue_type":"feature","owner":"rektide+git@voodoowarez.com","created_at":"2026-04-06T22:51:14Z","created_by":"rektide de la faye","updated_at":"2026-04-06T23:06:31Z","labels":["performance","streaming"],"dependency_count":0,"dependent_count":0,"comment_count":0}
11+{"id":"is-tree-sort-filter-date","title":"implement --sort, --filter, and --date flags","description":"## Overview\n\nis-tree needs `--sort`, `--filter`, and `--date` flags to control output ordering, filtering, and date formatting. These are currently documented in the README as aspirational features — this ticket tracks implementing them.\n\n## `--sort \u003ccolumn\u003e`\n\nSort output by one or more columns:\n- Multiple columns comma-separated\n- Suffix `+` for ascending, `-` for descending\n- Example: `--sort change-date-` (most recent first)\n- Example: `--sort status-,directory+`\n\nRequires sortable columns to be collected before output. For streaming mode (see `is-tree-scan-priority`), sort conflicts with streaming — when `--sort` is used, output must be buffered until all rows are collected. Without `--sort`, streaming is possible.\n\nColumns that should be sortable:\n- `status`, `directory`, `workparent`, `variant` (string)\n- `commit-date`, `change-date` (temporal)\n- `ahead` (numeric)\n\n## `--filter \u003ctype\u003e`\n\nFilter results by status type:\n- Comma-separated types: `git`, `jj`, `worktree`, `worktree-git`, `worktree-jj`\n- Suffix `-` for NOT: `git-` means \"not git\", `jj-` means \"not jj\"\n- Examples:\n - `--filter git` — only git repos\n - `--filter git,jj` — git or jj repos (exclude `none`)\n - `--filter worktree-` — exclude all worktrees\n\nUnlike `--sort`, filtering can happen early — skip detection work for excluded types. For scan-priority integration, pre-filtering reduces the work set.\n\n## `--date \u003cformat\u003e`\n\nDate format string using strftime-style patterns:\n- Default: ISO 8601\n- Example: `--date \"%Y-%m-%d %H:%M:%S\"`\n- Applied to `commit-date` and `change-date` columns\n- For the planned `duration`/`age` column (is-tree-duration-column), this would be ignored in favor of relative time formatting\n\n## Connection to scan priority (`is-tree-scan-priority`)\n\nSorting and scanning are deeply connected:\n\n1. **Without `--sort`**: streaming output is possible. Scan-priority determines emission order. Results appear as they're processed.\n2. **With `--sort`**: output must be buffered. But scan-priority still determines *processing order* — sort the final output after processing, but process the most relevant directories first so interactive users see early results even before sort completes.\n3. **Pre-filtering** reduces work. If `--filter jj` is set, skip git-only and bare directories during scan, not just in output.\n4. **Both at once**: `is-tree --all --filter jj --sort change-date-` should pre-filter to only jj trees during scan, process them in mtime-priority order, then output sorted by change-date descending.\n\n## Dependencies\n\n- Relates to `is-tree-scan-priority` — sort/filter/scan-priority need a unified design for how they interact during the processing pipeline.","status":"open","priority":1,"issue_type":"feature","owner":"rektide+git@voodoowarez.com","created_at":"2026-04-06T23:11:10Z","created_by":"rektide de la faye","updated_at":"2026-04-06T23:11:10Z","labels":["date","filter","output","sort"],"dependency_count":0,"dependent_count":0,"comment_count":0}
22+{"id":"is-tree-scan-priority","title":"Prioritized directory scanning: stream recently-changed projects first","description":"Currently is-tree processes directories in filesystem order and sorts after all results are collected. For large directory trees, this means waiting for the full scan before seeing the most relevant results.\n\nThis ticket tracks adding **scan priority** — deciding which directories to process first based on cheap heuristics, so the most interesting projects stream to screen immediately.\n\nKey aspects:\n\n1. **Pre-scan heuristics** — Use cheap filesystem metadata (mtime of the directory itself, presence of recent changes) to order the work queue before the heavier detection/formatting runs. `change-date` (file mtime) is essentially free from `stat` and correlates well with \"what am I working on.\"\n\n2. **Streaming output** — Emit results as each directory is processed, in priority order, rather than buffering everything. Combined with pre-scan ordering, the user sees their most-recently-worked-on projects first.\n\n3. **Atuin session priority** — Integrate with atuin session data (see is-tree-atuin-session-tracking) to boost directories associated with active sessions to the top of the scan queue.\n\n4. **Pre-filtering** — Allow filtering the scan set before processing (e.g. only scan directories modified in the last N days, or only directories with active sessions). This reduces total work for large trees.\n\n5. **New sort columns** — Add any additional sortable columns needed to support priority-aware output (e.g. session recency, directory mtime as a first-class column).","acceptance_criteria":"- Add `--scan` mode that performs lightweight discovery/classification only (`git`, `jj`, `worktree-git`, `worktree-jj`) without resolving expensive inspection columns.\n- `--scan` output streams line-by-line as candidates are found; users see early results before the full scan completes.\n- Default `--scan` output is one directory path per line (pipeline-safe), suitable for pickers and downstream commands.\n- Scan priority ordering still applies (recently changed first by default), and pre-filtering can reduce scan set.\n- Selected paths can flow back into deep inspection through stdin (`is-tree --scan | ... | is-tree --stdin --format all`, or equivalent auto-detected piped stdin behavior).\n- Existing non-scan behavior and explicit `--sort` post-processing remain compatible.","status":"open","priority":1,"issue_type":"feature","owner":"rektide+git@voodoowarez.com","created_at":"2026-04-06T22:51:14Z","created_by":"rektide de la faye","updated_at":"2026-04-06T23:06:31Z","labels":["performance","streaming"],"dependencies":[{"issue_id":"is-tree-scan-priority","depends_on_id":"is-tree-sort-filter-date","type":"related","created_at":"2026-04-06T19:11:13Z","created_by":"rektide de la faye","metadata":"{}"}],"dependency_count":0,"dependent_count":0,"comment_count":0}
23{"id":"is-tree-reforrest-starter","title":"scaffold reforrest project with gunshi-style CLI","description":"## Overview\n\nScaffold a new Rust project for `reforrest` as a separate crate, using `gunshi`-style CLI conventions. This is a prerequisite workspace setup ticket before implementing the actual push logic.\n\n## What it does\n\n- Create a new crate (e.g. `reforrest/` directory or workspace member) in the is-tree workspace.\n- Wire up `clap` derive CLI with initial subcommand structure:\n - `reforrest push [path]` — discover and push trees\n - `reforrest status [path]` — show what would be pushed (dry-run default)\n - `reforrest ensure-remote [path]` — create missing remotes via forge CLIs\n- Depend on `is-tree` as a library crate for tree detection/classification.\n- Basic `--dry-run`, `--json`, `--verbose` flags wired but not yet functional.\n- Skeleton `main.rs` with subcommand dispatch.\n\n## Key considerations\n\n- May require splitting is-tree into a lib+bin crate so reforrest can import detection logic.\n- Follow existing workspace conventions (Cargo.toml workspace, clap derive, tokio async).\n\n## Dependencies\n\n- This is a dependency of is-tree-reforrest-cli (the epic).","status":"open","priority":1,"issue_type":"task","owner":"rektide+git@voodoowarez.com","created_at":"2026-04-06T21:21:33Z","created_by":"rektide de la faye","updated_at":"2026-04-06T21:21:33Z","labels":["cli","gunshi","scaffold"],"dependency_count":0,"dependent_count":0,"comment_count":0}
34{"id":"is-tree-reforrest-cli","title":"reforrest: replicate local git and jj states to remotes","description":"## Overview\n\nCreate a `reforrest` CLI tool (Rust binary in this workspace) that discovers all local git/jj trees using is-tree's detection logic and pushes their local state up to tracked remotes — effectively \"making the trees flow out to far places.\"\n\n## What it does\n\nGiven a root directory (e.g. `~/src`), `reforrest`:\n\n1. **Discovers** all git and jj repositories/worktrees beneath the given path (leveraging is-tree's existing classification logic for `git`, `jj`, `worktree-git`, `worktree-jj`).\n2. **Inspects** each tree's local state relative to its tracked remote(s):\n - For jj repos: local bookmarks ahead of remote bookmarks, unpushed changes.\n - For git repos: local branches ahead of remote tracking branches.\n3. **Replicates** (pushes) local state up to remotes:\n - `jj git push --all` for jj trees.\n - `git push --all` for git trees.\n4. **Reports** a summary of what was pushed, what was skipped (up-to-date), and what failed (e.g. no remote configured, auth issues).\n\n## Architecture\n\n- New binary target `reforrest` in the existing `is-tree` Cargo workspace.\n- Reuse is-tree's detection/classification module as a library dependency.\n- Async push operations across discovered trees using tokio (already a dep).\n\n## Key considerations\n\n- Should be idempotent — safe to run repeatedly, no-ops when already synced.\n- Must handle mixed trees (some jj, some git, some worktrees) gracefully.\n- Worktrees: push from the main tree location, skip worktrees to avoid duplicate pushes.\n- Error handling: collect per-tree results, don't let one failure stop the rest. Report aggregate at end.\n- Respect `.gitignore`-style exclusions or a config for paths to skip.\n\n## Acceptance criteria\n\n- [ ] `reforrest ~/src` discovers all trees, classifies them, and pushes ahead state to remotes\n- [ ] Summary output shows pushed / up-to-date / failed / skipped counts per tree\n- [ ] Handles jj repos, git repos, and worktrees correctly\n- [ ] Worktrees are deduplicated (push happens from main tree only)\n- [ ] Individual tree failures don't abort the batch; errors are collected and reported\n- [ ] `--dry-run` flag shows what would be pushed without actually pushing\n- [ ] `--json` flag for machine-readable output","status":"open","priority":1,"issue_type":"epic","owner":"rektide+git@voodoowarez.com","created_at":"2026-04-06T21:11:32Z","created_by":"rektide de la faye","updated_at":"2026-04-06T21:11:32Z","labels":["cli","push","replication"],"dependency_count":0,"dependent_count":0,"comment_count":0}
45{"id":"is-tree-atuin-session-tracking","title":"Atuin session tracking: find which sessions last cd'ed into each directory","description":"Track which atuin sessions last cd'ed into each directory, leveraging ATUIN_SESSION to correlate shell sessions with directory changes. This enables answering \"which session am I in that project from?\" and \"which session was last working here?\" across the is-tree project listing.\n\nThree integration layers:\n\n1. **Query atuin DB directly** — Read the atuin SQLite DB (~/.local/share/atuin/history.db or equivalent) to find `cd` commands grouped by session (ATUIN_SESSION). Map session IDs to the directories they last visited. This is the data foundation.\n\n2. **Shell hook / env integration** — Use ATUIN_SESSION env var at runtime to associate the current shell session with the working directory. Could be a hook that records session→directory mappings, or reads them on-demand from atuin history keyed by session.\n\n3. **New CLI subcommand** — Add an is-tree subcommand (e.g. `is-tree sessions` or integrated into `--all` output) that reports per-directory session info from atuin history. Show which session last cd'ed into each tree, when, and potentially the session's current/last-known directory.","acceptance_criteria":"- Can query atuin history DB for cd commands grouped by ATUIN_SESSION\n- Shell hook or integration surface exists to resolve current session's directory from ATUIN_SESSION\n- New subcommand or column shows session info alongside is-tree directory listings\n- Works with both git and jj trees","status":"open","priority":2,"issue_type":"feature","owner":"rektide+git@voodoowarez.com","created_at":"2026-04-06T22:29:20Z","created_by":"rektide de la faye","updated_at":"2026-04-06T22:29:20Z","labels":["atuin","session-tracking"],"dependency_count":0,"dependent_count":0,"comment_count":0}
+62-32
README.md
···1111# Test all directories in current path with --all/-a
1212is-tree --all
13131414-# Filter for specific types (comma-separated, - for NOT)
1515-is-tree --all --filter git
1616-is-tree --all --filter git,jj
1717-is-tree --all --filter worktree-git,worktree-jj
1818-is-tree --all --filter worktree-
1919-is-tree --all --filter git-,jj
2020-2114# Test specific directories by positional arguments
2215is-tree ~/src/compfuzor ~/src/niri-mcp
23162424-# Sort by any column (use + for ascending, - for descending)
2525-is-tree --all --sort change-date-
2626-is-tree --all --sort commit-date+
2727-is-tree --all --sort workparent,directory+
2828-2929-# Multiple sorts (comma-separated)
3030-is-tree --all --sort status-,change-date+
3131-3217# Custom output format with interpolated columns
3333-is-tree --all --format "{status} {directory} {commit-date} {change-date} {workparent}"
3418is-tree --all --format "{status} {directory} {ahead}"
3519is-tree --all --format all
36202121+# Enable jj plugin columns
2222+is-tree --all --jj
2323+3724# Output as JSON (respects --format for column selection)
3825is-tree --all --json
3926is-tree --all --format "{status} {directory} {ahead}" --json
40272828+# Header row with custom separator
2929+is-tree --all --header --separator " | "
3030+```
3131+3232+### Planned usage (not yet implemented)
3333+3434+```bash
3535+# Filter for specific types (comma-separated, - for NOT)
3636+is-tree --all --filter git
3737+is-tree --all --filter git,jj
3838+is-tree --all --filter worktree-
3939+is-tree --all --filter git-,jj
4040+4141+# Sort by any column (use + for ascending, - for descending)
4242+is-tree --all --sort change-date-
4343+is-tree --all --sort workparent,directory+
4444+4145# Custom date format
4246is-tree --all --date "%Y-%m-%d %H:%M:%S"
4347```
44484549## Options
46504747-- `--all`, `-a` - Test all directories in current path
4848-- `--filter <type>` - Filter by type(s). Multiple types comma-separated. Suffix `-` for NOT. Types: `git`, `jj`, `worktree`, `worktree-git`, `worktree-jj`
4949-- `--sort <column>` - Sort by column(s). Multiple columns comma-separated. Suffix `+` for ascending, `-` for descending
5050-- `--format <string>` - Custom output format with interpolated columns
5151- - Shortcut: `--format all` includes all available columns
5252-- `--date <format>` - Date format string (default: ISO 8601)
5353-- `--json` - Output results in JSON format
5454-- Positional arguments - Test specific directories
5151+### Implemented
5252+5353+| Flag | Description |
5454+|------|-------------|
5555+| `--all`, `-a` | Scan all non-hidden subdirectories in current directory |
5656+| `--format <template>` | Output format with `{column}` placeholders; `all` for every column |
5757+| `--json` | Output as JSON array (respects `--format` for column selection) |
5858+| `--header` | Print a header row above text output |
5959+| `--separator <string>` | Replace spaces between columns in text output (default: single space) |
6060+| `--plugins <ids>` | Comma-separated plugin ids to run (default: all) |
6161+| `--microbatch-rows <n>` | Max row patches per streaming microbatch (default: 64) |
6262+| `--jj` | Enable jj plugin columns (equivalent to requesting all jj columns) |
6363+| `--jj-ahead` | Enable the `ahead` column |
6464+| `<directories>` | Positional paths to inspect |
6565+6666+### Not yet implemented
6767+6868+| Flag | Description | Ticket |
6969+|------|-------------|--------|
7070+| `--filter <type>` | Filter by repo type: `git`, `jj`, `worktree`, `worktree-git`, `worktree-jj`. Suffix `-` for NOT | [is-tree-sort-filter-date] |
7171+| `--sort <column>` | Sort by column(s). Suffix `+` ascending, `-` descending | [is-tree-sort-filter-date] |
7272+| `--date <format>` | strftime-style date format (default: ISO 8601) | [is-tree-sort-filter-date] |
55735674## Output
57755876Default format: `<status> <directory>`
59776078### Columns
6161-Available columns for custom format:
6262-- `status` - Repository type (git, jj, worktree-git, worktree-jj, none)
6363-- `directory` - Full directory path
6464-- `workparent` - Directory name of the workparent (without path), for worktrees only
6565-- `commit-date` - Most recent commit date
6666-- `change-date` - Most recent file change date
6767-- `ahead` - Number of local JJ commits ahead of tracked remote bookmarks
7979+8080+Available columns for `--format`:
8181+8282+**Implemented:**
8383+8484+| Column | Description | Source |
8585+|--------|-------------|--------|
8686+| `status` | Repository type (git, jj, worktree-git, worktree-jj, none) | core |
8787+| `directory` | Full directory path | core |
8888+| `ahead` | Local JJ commits ahead of tracked remote bookmarks | `--jj` / `--jj-ahead` |
8989+9090+**Not yet implemented:**
9191+9292+| Column | Description | Ticket |
9393+|--------|-------------|--------|
9494+| `workparent` | Directory name of the workparent (worktrees only) | [is-tree-sort-filter-date] |
9595+| `commit-date` | Most recent commit date | [is-tree-sort-filter-date] |
9696+| `change-date` | Most recent file change date | [is-tree-sort-filter-date] |
68976998### Status values
7099- `git` - Git repository (not Jujutsu, not a worktree)
···128157129158### Interaction & workflows
130159160160+- **[is-tree-sort-filter-date]** `--sort`, `--filter`, `--date` flags for controlling output ordering, type filtering, and date formatting.
161161+- **[is-tree-scan-priority]** Stream recently-changed projects first during scans.
131162- **[is-tree-interactive-picker]** Built-in TUI picker with fuzzy search and multi-select for choosing trees.
132163- **[is-tree-fuzzel-pipeline]** Documented example pipeline: `is-tree --all --format "{directory}" | fuzzel --dmenu --multi`.
133133-- **[is-tree-scan-priority]** Stream recently-changed projects first during scans.
134164- **[is-tree-semantic-search]** Semantic search across trees via opencode run / ACP.