# `/tree` Command Reference

`/tree` opens the interactive **Session Tree** navigator. It lets you jump to any entry in the current session file and continue from that point.

This is an in-file leaf move, not a new session export.

## What `/tree` does

- Builds a tree from current session entries (`SessionManager.getTree()`)
- Opens `TreeSelectorComponent` with keyboard navigation, filters, and search
- On selection, calls `AgentSession.navigateTree(targetId, { summarize, customInstructions })`
- Rebuilds visible chat from the new leaf path
- Optionally prefills editor text when selecting a user/custom message

Primary implementation:

- `src/slash-commands/builtin-registry.ts` (`/tree`, `/branch` command routing)
- `src/modes/controllers/input-controller.ts` (keybinding wiring, double-escape behavior)
- `src/modes/controllers/selector-controller.ts` (tree UI launch + summary prompt flow)
- `src/modes/components/tree-selector.ts` (navigation, filters, search, labels, rendering)
- `src/session/agent-session.ts` (`navigateTree` leaf switching + optional summary)
- `src/session/session-manager.ts` (`getTree`, `branch`, `branchWithSummary`, `resetLeaf`, label persistence)

## How to open it

Any of the following opens the same selector:

- `/tree`
- configured keybinding for the `app.session.tree` action
- double-escape on empty editor when `doubleEscapeAction = "tree"` (default)
- `/branch` when `doubleEscapeAction = "tree"` (routes to tree selector instead of user-only branch picker)

## Tree UI model

The tree is rendered from session entry parent pointers (`id` / `parentId`).

- Children are sorted by timestamp ascending (older first, newer lower)
- Active branch (path from root to current leaf) is marked with a bullet
- Labels (if present) render as `[label]` before node text
- If multiple roots exist (orphaned/broken parent chains), they are shown under a virtual branching root

```text
Example tree view (active path marked with •):

├─ user: "Start task"
│  └─ assistant: "Plan"
│     ├─ • user: "Try approach A"
│     │  └─ • assistant: "A result"
│     │     └─ • [milestone] user: "Continue A"
│     └─ user: "Try approach B"
│        └─ assistant: "B result"
```

The selector recenters around current selection and shows up to:

- `max(5, floor(terminalHeight / 2))` rows

## Keybindings inside tree selector

- `Up` / `Down`: move selection (wraps)
- `Left` / `Right`: page up / page down
- `Enter`: select node
- `Esc`: clear search if active; otherwise close selector
- `Ctrl+C`: close selector
- `Type`: append to search query
- `Backspace`: delete search character
- `Shift+L`: edit/clear label on selected entry
- `Ctrl+O`: cycle filter forward
- `Shift+Ctrl+O`: cycle filter backward
- `Alt+D/T/U/L/A`: jump directly to specific filter mode

## Filters and search semantics

Filter modes (`TreeList`):

1. `default`
2. `no-tools`
3. `user-only`
4. `labeled-only`
5. `all`

### `default`

Shows conversational nodes plus any entry types not explicitly suppressed. It hides these setting/bookkeeping entry types:

- `label`
- `custom`
- `model_change`
- `thinking_level_change`

Other internal entry types that are not rendered specially may appear as blank rows in current code.

### `no-tools`

Same as `default`, plus hides `toolResult` messages.

### `user-only`

Only `message` entries where role is `user`.

### `labeled-only`

Only entries that currently resolve to a label.

### `all`

Everything in the session tree, including bookkeeping/custom entries.

### Tool-only assistant node behavior

Assistant messages that contain **only tool calls** (no text) are hidden by default in all filtered views unless:

- message is error/aborted (`stopReason` not `stop`/`toolUse`), or
- it is the current leaf (always kept visible)

### Search behavior

- Query is tokenized by spaces
- Matching is fuzzy (subsequence) and case-insensitive (`fuzzyMatch`)
- All tokens must match (AND semantics)
- Searchable text includes label, role, and type-specific content (message text, branch summary text, custom type, tool command snippets, etc.)

## Selection outcomes (important)

`navigateTree` computes new leaf behavior from selected entry type:

### Selecting `user` message

- New leaf becomes selected entry’s `parentId`
- If parent is `null` (root user message), leaf resets to root (`resetLeaf()`)
- Selected message text is copied to editor for editing/resubmit

### Selecting `custom_message`

- Same leaf rule as user messages (`parentId`)
- Text content is extracted and copied to editor

### Selecting non-user node (assistant/tool/summary/compaction/custom bookkeeping/etc.)

- New leaf becomes selected node id
- Editor is not prefilled

### Selecting current leaf

- No-op; selector closes with “Already at this point”

```text
Selection decision (simplified):

selected node
   │
   ├─ is current leaf? ── yes ──> close selector (no-op)
   │
   ├─ is user/custom_message? ── yes ──> leaf := parentId (or resetLeaf for root)
   │                                     + prefill editor text
   │
   └─ otherwise ──> leaf := selected node id
                    + no editor prefill
```

## Summary-on-switch flow

Summary prompt is controlled by `branchSummary.enabled` (default: `false`).

When enabled, after picking a node the UI asks:

- `No summary`
- `Summarize`
- `Summarize with custom prompt`

Flow details:

- Escape in summary prompt reopens tree selector
- Custom prompt cancellation returns to summary choice loop
- During summarization, UI shows loader and binds `Esc` to `abortBranchSummary()`
- If summarization aborts, tree selector reopens and no move is applied

`navigateTree` internals:

- Collects abandoned-branch entries from old leaf to common ancestor
- Emits `session_before_tree` (extensions can cancel or inject summary)
- Uses default summarizer only if requested and needed
- Applies move with:
  - `branchWithSummary(...)` when summary exists
  - `branch(newLeafId)` for non-root move without summary
  - `resetLeaf()` for root move without summary
- Replaces agent conversation with rebuilt session context
- Emits `session_tree`

Note: if user requests summary but there is nothing to summarize, navigation proceeds without creating a summary entry.

## Labels

Label edits in tree UI call `appendLabelChange(targetId, label)`.

- non-empty label sets/updates resolved label
- empty label clears it
- labels are stored as append-only `label` entries
- tree nodes display resolved label state, not raw label-entry history

## `/tree` vs adjacent operations

| Operation | Scope                                            | Result                                                                                                                                                   |
| --------- | ------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `/tree`   | Current session file                             | Moves leaf to selected point (same file)                                                                                                                 |
| `/branch` | Usually current session file -> new session file | By default branches from selected **user** message into a new session file; if `doubleEscapeAction = "tree"`, `/branch` opens tree navigation UI instead |
| `/fork`   | Whole current session                            | Duplicates session into a new persisted session file                                                                                                     |
| `/resume` | Session list                                     | Switches to another session file                                                                                                                         |

Key distinction: `/tree` is a navigation/repositioning tool inside one session file. `/branch`, `/fork`, and `/resume` all change session-file context.

## Operator workflows

### Re-run from an earlier user prompt without losing current branch

1. `/tree`
2. search/select earlier user message
3. choose `No summary` (or summarize if needed)
4. edit prefilled text in editor
5. submit

Effect: new branch grows from selected point within same session file.

### Leave current branch with context breadcrumb

1. enable `branchSummary.enabled`
2. `/tree` and select target node
3. choose `Summarize` (or custom prompt)

Effect: a `branch_summary` entry is appended at the target position before continuing.

### Investigate hidden bookkeeping entries

1. `/tree`
2. press `Alt+A` (all)
3. search for `model`, `thinking`, `custom`, or labels

Effect: inspect full internal timeline, not just conversational nodes.

### Bookmark pivot points for later jumps

1. `/tree`
2. move to entry
3. `Shift+L` and set label
4. later use `Alt+L` (`labeled-only`) to jump quickly

Effect: fast navigation among durable branch landmarks.
