Repository navigation
Description
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/apifrom three hosts becomes one group, and nothing tells me which row ran where. - Group labels keep only the last two path segments.
work/apion two hosts, or twoapicheckouts 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.
- Workspace scope compares cwd strings (
- 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 recordedcwd. - 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
cwdAliasesand keep today's behaviour.
- On the host that scans (desktop or orcad), scope paths are passed through
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 atai-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.
- In All hosts, each Orca server gets
- Fork (F044): If the server's environment record has
connectionDependency: 'ssh-tunnel'(an orcad deployed over SSH, or SSH access), it getssshScanRelay= 15 s. LAN or Tailscale direct servers, and records that can't be read, stay at 3 s.
6. Smaller related changes
- Long tool output in search:
- Today, the search index keeps only the first 3072 characters of each tool output (
TOOL_ROW_CHARS). An error near the end of a long build log can't be found. - The fork splits tool output into ~8000-character chunks, as it already does for messages, and bumps the index schema by 1 so old indexes are rebuilt.
- Today, the search index keeps only the first 3072 characters of each tool output (
- Scanner memory on large histories:
- The scanner child process has a fixed 384 MiB heap (
session-scanner-service-spawn.ts#L44). - The fork sizes it to ¼ of RAM: never below 384 MiB, capped at 2 GiB, and always leaving 2 GiB free. Related reports: [Bug]: Agent Session History never completes on large Claude Code histories: 130s scan deadline + no partial cache persistence causes an endless timeout loop ("No agent sessions found") #26175, fix(session-history): scoped history no longer fails on a very large transcript corpus #30905.
- The scanner child process has a fixed 384 MiB heap (
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
- Overview, in Chinese: FORK-CHANGES.md: F022, F044, and the "历史会话" section
- Behaviour checklist with scan measurements (Chinese): docs/fork/parity/ai-vault.md
- Hooks into upstream files: docs/fork/HOOKS.md and src/shared/fork-hooks/ai-vault.ts
- Renderer: src/fork/ai-vault/
list-presentation.ts: host partition, labels, search host labelsuse-list-presentation.tsx: collapse-new, collapse-all, menu contexthost-menu.ts: which hosts go into "Other configured hosts"register-renderer.tsx: what is registered, including the All hosts default
- Main / orcad: src/fork/main/ai-vault/
- Alias matching in shared code: src/shared/fork-hooks/ai-vault-cwd.ts
- Representative commits:
Base version
- Fork
developatdbe6ab88d5. - It includes upstream
stablyai/orcamainatdd85af1434(Oct 19, 2026, fix(automations): headless keeps finished per-run sessions asleep instead of closing them (#24208) #30639). - Compared against upstream
mainat5f1a66a5cb(Oct 20, 2026, fix(i18n): clarify terminal agent and chat UI switch labels #31134). The AI Vault commits between the two don't touch grouping, the host menu, scope matching or the all-hosts budget. - The app reports version 1.4.228.
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
- [Feature]: Name remote hosts in session search and suggest projects from agent history #23448 / feat(ai-vault): name remote hosts and suggest projects from agent session history #23449 (open) name remote hosts in session search, using the SSH target labels, and keep the names while a host is disconnected. That overlaps use case 3 and goes further. If it lands, the fork's badge can go. The fork shows the badge only when hits span 2+ hosts, which may be worth keeping.
- [Bug]: History host picker misses CLI-paired servers until the catalog refreshes elsewhere #25251 / fix(history): discover CLI-paired servers when opening the host picker #25355 (open) refresh the host picker's catalog on open. That's complementary to use case 2: discovery first, then fold the hosts that aren't in use.
- Agent Session History misses sessions on SSH hosts managed by a paired Orca server #27394 (open): sessions on SSH hosts managed by a paired server are missing. It's in the same multi-host area as use case 5, but it's a different gap (routing, not the budget).
- [Feature]: Session History – show N most recent sessions per project #27960 / feat(session-history): cap sessions shown per group with Show more #27970 (open) cap sessions per group with "Show more". That's complementary to collapsed-by-default groups.
- [Bug]: Agent Session History merges two unrelated folders that share a git remote URL (project id keyed by remote canonicalKey) #28589 (open): unrelated folders merged by project identity. It's a similar "different things collapse into one group" problem to use case 1, but across folders rather than hosts.
Suggestions for an upstream design (optional)
- 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.
- 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.
- Rank the host menu by use (active, connected, has history) and fold the rest into a submenu.
- Resolve scope paths with
realpathon the scanning host, and carry the matching-only aliases (e.g.cwdAliases) next to the recordedcwd. That way, resume never changes paths. - 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
nwparker commentedon Oct 20, 2026
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:
connectionDependency: 'ssh-tunnel'now gets 15 s; direct servers keep 3 s.realpathof the scope paths and scans both spellings. Matching sessions get optional, matching-onlycwdAliases, and the Workspace filter, depth cap and project attribution read them. Resume still uses the recorded cwd, and older peers ignore the field.realpathon 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.Deferred as follow-ups, so this issue stays open:
Also not in scope here: All hosts as the default scope, chunked tool-output indexing, and heap sizing for the scanner.
fix(ai-vault): give Orca servers reached over SSH the 15 s all-hosts …
fix(ai-vault): keep sessions recorded under a symlinked workspace's r…
feat(ai-vault): name the host each search hit came from when hits spa…