Files
tty7/docs/remote/port-forwarding.mdx
l0ng-ai 6fcf659e04 feat(search): tabbed Search Everywhere with a Sessions tab to resume agent sessions (#969)
* feat(search): replace the command palette with tabbed Search Everywhere

The palette was one flat list that every new kind of row had to be squeezed
into: tabs and SSH hosts rode along as "Switch to Tab: …" and "SSH: …"
commands, and the only way to narrow to one kind was a magic seed word.

Search Everywhere splits it into sources behind one trait — All, Actions,
Terminals, Hosts — each with its own empty-query layout and ranking. The All
tab shows each source's top rows, ordered by best match, with a row that
opens the full tab. Tab / Shift-Tab walk the tabs and keep the query.

- Terminals lists every open tab of every workspace (reusing the switcher's
  tab rows) and jumps to it wherever it lives, plus the shells and agents.
- Hosts replaces the separate "Add Connection" input: a typed address or
  full `ssh …` line offers to connect.
- Fixes Return doing nothing after a search that found nothing, or when the
  search opens pre-filtered: gpui-component re-picks the row from a stale
  frame; the delegate now re-arms the first row.
- Fixes `ssh -p 2222 me@box` being offered as a quick-connect address with
  user `ssh -p 2222 me`.

The keymap action stays `TogglePalette` so custom bindings keep working.

* feat(search): a Sessions tab to resume past agent sessions

Search Everywhere gains a Sessions tab listing the Claude Code and Codex
sessions on this computer, read from ~/.claude/projects and
~/.codex/sessions ($CODEX_HOME). Sessions that ran in the focused tab's
directory lead; the All tab offers the last three of them before anything
is typed. Return opens a new tab in the session's directory and runs the
agent's resume command with its configured launch flags.

- Only each transcript's head and tail are read, off the window thread,
  and cached by path, size and mtime: ~170ms cold for 50 sessions,
  under 1ms warm. The search opens on the cached list and fills in.
- Titles: /rename name, then the agent's own title (ai-title, Codex's
  session_index.jsonl), then the first thing typed, skipping harness
  injections. Codex rollouts it ran for itself (subagent/internal) and
  sessions never asked anything are left out.
- A session whose directory is gone is refused with a notice rather than
  resumed where the agent cannot find it.
2026-09-27 09:38:31 +08:00

114 lines
4.7 KiB
Plaintext

---
title: "Port forwarding"
description: "Local, remote, and dynamic forwards — preconfigured or added mid-session."
---
## Ports you did not ask to forward
When a pane is on a remote machine, tty7 watches what its processes are
listening on and forwards those ports for you. Start a dev server on the remote
`:3000` and a moment later a notice says it is at `http://localhost:3000` —
same number, no rule to write.
The **Ports** section of the Info panel is the whole list: one row per listener,
the process that owns it, and where it comes out on this machine. The globe
opens it in a browser, the copy tile takes the address that works from here,
and ✕ takes the forward back down.
Ports are forwarded once each. Remove one and it stays removed — the offer is
made a single time per port, not on every poll.
The local port matches the remote one whenever it is free here. When it is not —
something else on this machine already has `:3000` — the OS picks another and
the row says which.
Turn the whole thing off under **Settings → Terminal → Links → Forward remote
ports** (`ssh_loopback_forward: false`).
<Note>
In a remote workspace the ports are found by the **`tty7-server` on that
machine** — the panes are its, and this machine's daemon has never heard of
them. A server too old to answer says so in the Ports section rather than
showing an empty list; updating it is what fixes that. Panes that ssh'd
somewhere from inside a local pane are a different case: those processes
belong to no tty7 server, so nothing lists them.
</Note>
## The three kinds
| | What it does |
|---|---|
| **Local** (`L`) | A port on this machine reaches a service on the remote side |
| **Remote** (`R`) | A port on the remote machine reaches a service here |
| **Dynamic** (`D`) | A SOCKS proxy on this machine, routed through the connection |
## Adding one to a profile
**Settings → SSH →** a profile **→ Port forwarding → + Add rule**. Rules saved
here open with the connection, every time.
A Local or Remote rule needs a listen port and a target; a Dynamic rule needs
only the listen port. An incomplete rule tells you so rather than being saved
half-configured.
Each rule takes an optional description — *"what it's for"* — because six months
later `8080 → 3000` explains nothing.
## Adding one mid-session
The **+** on the Ports section — or *SSH: Port Forwarding* in Search
Everywhere — opens a form asking for one thing: the port the remote is serving on.
It comes out here under the same number, and the form says so before you commit
to it.
**Advanced** opens the rest of the grammar: remote and dynamic forwards, a bind
host other than loopback, a target on some third machine, a description. You
need it about as often as you need `ssh -R`.
These live only as long as the session unless you save them into the profile.
## Switching a rule off
Every forward in the Ports section has a switch. Off, the forward lets go of
its port but keeps its whole rule — kind, ports, target, description — so it
can be switched back on without retyping anything. That is how one local port
is pointed at different places: keep one rule per target on the same port, and
switch on the one you want.
Only one of them can hold the port at a time. Switching one on while another
still has its port is refused, and the notice names the forward to switch off
first.
Rules from a profile carry their switch into it, so the next connection opens
the same set. The same switch sits beside each rule under **Settings → SSH →**
a profile **→ Port forwarding**; a rule saved switched off is listed but not
opened. Rules added mid-session are still gone when the session ends, on or
off.
<Frame caption="The Ports section with a local forward and a dynamic (SOCKS) rule">
<img src="/images/ports.webp" alt="The ports section" />
</Frame>
## Links in the terminal
<kbd>⌘</kbd>-clicking a `localhost:PORT` link inside a remote pane opens the
forward for that port if there is not one yet, then the browser. Same machinery
as the Ports list, reached from the output instead of the panel.
## Jump hosts and proxies
Multi-hop connections are configured per profile:
- **Jump host** — point at another saved profile, or use a `ProxyJump` chain
- **ProxyCommand** — an arbitrary transport command, with `%h`, `%p`, `%r`
substituted
- **SOCKS5 proxy** / **HTTP proxy** — `host:port`, under **Advanced → Proxies**
<Note>
These proxy settings are for reaching the SSH server. tty7's *own* network
traffic — update checks, release downloads, remote-server installs — uses
`http_proxy` in `config.json`, the system proxy, or the `HTTP_PROXY` family.
Programs running in a pane are unaffected either way; they inherit their proxy
from their own environment, as in any terminal.
</Note>