Skip to content

[Feature]: Session History across several hosts: host → directory grouping, a shorter host menu, source host on search hits, symlinked workspaces, and a longer all-hosts budget for Orca servers reached over SSH #31139

Open

Description

@quzard

Summary

I maintain a fork, quzard/orca-fork. I work on the local machine plus several SSH hosts and Orca servers. The fork changes Agent Session History (AI Vault) for that setup:

  • In All hosts, sessions are grouped by host, then by directory.
  • The host menu is shorter.
  • When results come from more than one host, search hits show which host each came from.
  • Sessions recorded under a workspace's real path (behind a symlink) still match that workspace.
  • Orca servers reached over an SSH tunnel get the same all-hosts scan budget as SSH hosts.

The fork is upstream main plus small fork hooks. This issue explains the use cases so you can decide what belongs upstream. It is not a request to merge the fork. Anything current upstream already does as well has been left out.

Use cases / why it's needed

1. Browsing history across several hosts

I open History to find "the session I ran in api on devbox yesterday". The same directory, e.g. /home/me/src/api, exists on the laptop, devbox and build-host.

  • Pain today:
    • History opens on the active workspace's host (local when no workspace is open). Sessions on other hosts don't appear until I switch the menu by hand.
    • In All hosts, Folder grouping (and the folder fallback of Project grouping) keys groups by path only (folderGroupKey). So /home/me/src/api from three hosts becomes one group, and nothing tells me which row ran where.
    • Group labels keep only the last two path segments. work/api on two hosts, or two api checkouts under different parents, look the same.
    • Every group starts expanded. With several hosts, the list is very long.
  • Fork:
    • The default scope is All hosts.
    • With 2+ hosts in the list, each host gets a collapsible host row, and its directory groups sit under it. The same path on two hosts makes two groups. With one host, there's no extra host row.
    • Directory labels show the full path and wrap instead of truncating.
    • New host and directory groups start collapsed. One header button collapses everything.
    • A one-line status shows "Scanning history…" while scanning and "N hosts" afterwards.

2. A host menu with many configured hosts

I have a dozen SSH targets and a few Orca servers configured. Most have no agent history, or aren't connected right now.

  • Pain today: The host menu is a flat list of every known host (ai-vault-host-scope.ts). The two or three hosts I actually use are buried.
  • Fork:
    • The top level keeps All hosts, Local, the active workspace's host, connected SSH targets, and any host with sessions in the current list.
    • The remaining hosts move into an Other configured hosts submenu. They can still be selected there.

3. Telling search hits apart by host

A full-text search in All hosts returns one flat list in hit order. The same title or path often comes up on two hosts.

  • Pain today: Before resuming, I can't tell which machine a hit came from. Resuming the wrong copy opens the wrong host.
  • Fork:
    • When the hits span 2+ hosts, each row gets a small host badge.
    • Hit order is unchanged. Results aren't regrouped.
    • With hits from a single host, there's no badge.

4. Workspaces opened through a symlink

A workspace is registered as ~/work/api, which is a symlink to /data/src/api (on macOS, also /var → /private/var). Some agents record the resolved cwd.

  • Pain today:
    • Workspace scope compares cwd strings (createAiVaultScopeCwdMatcher), so these sessions fall outside the Workspace scope.
    • They also count against the out-of-scope depth cap, so they can disappear from the list entirely.
  • Fork (F022):
    • On the host that scans (desktop or orcad), scope paths are passed through realpath.
    • Matching sessions get optional cwdAliases. Aliases are used only for scope matching, the depth cap and project/worktree attribution. Resume still uses the recorded cwd.
    • When two workspaces match, the longer (more specific) path wins, so a parent folder doesn't take a child repo's sessions.
    • A cwd recorded through another symlink, or one that no longer exists, is matched by resolving its deepest existing parent. Each distinct cwd is resolved once per scan, and only when there are aliases.
    • All hosts sends the same scope paths to every host. A path that doesn't exist on a host (ENOENT/ENOTDIR) is skipped quietly, as upstream does today. A broken link or a permission error is reported as a scope issue.
    • Older hosts don't send cwdAliases and keep today's behaviour.

5. All hosts with an Orca server reached over SSH

My managed servers are deployed over SSH, so Orca reaches each one through an SSH tunnel.

  • Pain today:
    • In All hosts, each Orca server gets runtimeScan = 3 s (ai-vault-all-host-timeouts.ts, used at ai-vault.ts#L159).
    • The comment in the same file explains that 3 s "emptied healthy SSH hosts", which is why the SSH relay got 15 s. A server reached over a tunnel walks the same home directory, plus tunnel latency.
    • Such a server often times out and shows up empty in All hosts, even though selecting it alone works.
  • Fork (F044): If the server's environment record has connectionDependency: 'ssh-tunnel' (an orcad deployed over SSH, or SSH access), it gets sshScanRelay = 15 s. LAN or Tailscale direct servers, and records that can't be read, stay at 3 s.

6. Smaller related changes

What the fork does (summary)

  • All hosts by default. Host → directory grouping with full, wrapped directory labels. Collapsed-by-default groups, a collapse-all button, and a host-count/scanning status line.
  • Host menu: rarely used hosts go into an Other configured hosts submenu.
  • Host badge on search hits when the results span 2+ hosts; hit order unchanged.
  • Symlink-aware workspace scope (cwdAliases) on desktop and orcad, also used by the depth cap and attribution. Resume uses the original cwd.
  • A 15 s all-hosts budget for Orca servers reached over an SSH tunnel.
  • Chunked tool-output indexing and a heap sized to the machine's memory.

Where to look

Base version

Already in upstream (not requested)

  • Per-host caching: the renderer result cache (ai-vault-session-result-cache.ts) and the per-host leg cache in main (ai-vault-host-leg-cache.ts). The fork dropped its own host cache: in my measurements, upstream's warm scan was already ~10 ms.
  • History depth: the depth menu plus truncateAiVaultListResult. The fork only makes the cap alias-aware (use case 4).

Overlap with current upstream work

Suggestions for an upstream design (optional)

  1. When All hosts is selected and 2+ hosts are present, add the host to the group key (host → directory/project). Keep search hits flat and in rank order.
  2. Consider All hosts as the default scope, or as a remembered choice, for multi-host users. [Bug] No corresponding agent session found in SSH #13713 already widens the default when the workspace host is unresolved.
  3. Rank the host menu by use (active, connected, has history) and fold the rest into a submenu.
  4. Resolve scope paths with realpath on the scanning host, and carry the matching-only aliases (e.g. cwdAliases) next to the recorded cwd. That way, resume never changes paths.
  5. Choose each Orca server's all-hosts budget by how it's reached: tunnelled servers get the SSH relay budget, direct ones keep 3 s. Alternatively, return partial results instead of an empty host.

Related issues: #23448, #23449, #25251, #25355, #27394, #27960, #27970, #28589, #13713, #26175, #30905, #30342.

Activity

  1. nwparker commented on Oct 20, 2026

    @nwparker
    Contributor

    Thanks @quzard, this was a very clear write-up, and the fork made the trade-offs easy to see. The correctness parts are now in three small PRs, each following your proposed approach:

    • Item 5, the all-hosts budget for Orca servers reached over SSH: fix(ai-vault): give Orca servers reached over SSH the 15 s all-hosts scan budget #31226. Since the SSH relay client was removed, every SSH host is served by an Orca server through a tunnel. So all of them were getting the 3 s budget, which is worse than the issue describes. A server whose saved environment has connectionDependency: 'ssh-tunnel' now gets 15 s; direct servers keep 3 s.
    • Item 4, symlinked workspaces: fix(ai-vault): keep sessions recorded under a symlinked workspace's real path in Workspace scope #31244. The host that owns the files (the desktop for local scans, orcad for SSH and server hosts) resolves realpath of the scope paths and scans both spellings. Matching sessions get optional, matching-only cwdAliases, and the Workspace filter, depth cap and project attribution read them. Resume still uses the recorded cwd, and older peers ignore the field.
      • Differences from the fork: a cwd recorded through a different link is not resolved. Calling realpath on every recorded cwd could stall a listing on a hung network mount, or raise macOS privacy prompts. Workspace-scope search still matches exact paths; that's a follow-up.
    • Item 3, the source host on search hits: feat(ai-vault): name the host each search hit came from when hits span several hosts #31261. When hits span 2+ hosts, each row shows the same host chip the sidebar uses, labelled the way the host menu names that host. Hit order is unchanged.

    Deferred as follow-ups, so this issue stays open:

    1. Host -> directory grouping under All hosts, with full directory labels.
    2. A shorter host menu, with rarely used hosts folded into an "Other configured hosts" submenu.
    3. Collapsed-by-default groups, a collapse-all control, and the scanning / host-count status line.

    Also not in scope here: All hosts as the default scope, chunked tool-output indexing, and heap sizing for the scanner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions