https://github.com/iurysza/termscope
Open files and links already visible on your terminal screen.
https://github.com/iurysza/termscope
herdr herdr-plugin python television terminal tmux
Last synced: 3 days ago
JSON representation
Open files and links already visible on your terminal screen.
- Host: GitHub
- URL: https://github.com/iurysza/termscope
- Owner: iurysza
- License: mit
- Created: 2026-06-22T15:57:03.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-07-18T05:58:10.000Z (8 days ago)
- Last Synced: 2026-07-18T07:21:40.372Z (8 days ago)
- Topics: herdr, herdr-plugin, python, television, terminal, tmux
- Language: Python
- Homepage: https://github.com/iurysza/termscope
- Size: 746 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- License: LICENSE
- Security: SECURITY.md
Awesome Lists containing this project
README
# termscope

[](https://github.com/iurysza/termscope/actions/workflows/ci.yml)
[](LICENSE)


Open the files and links your agent just mentioned.
`termscope` turns terminal output into a jump list. It reads the active pane's
visible terminal viewport, finds real files and URLs, then opens the selected
target beside the conversation you were already reading.
```text
visible terminal viewport
│
▼
Ctrl-Shift-A → pick a visible file → nvim opens src/main.py:42
Ctrl-E → pick a visible link → browser opens it
```
## Demo
https://github.com/user-attachments/assets/af573bbc-abf9-4947-9ed6-955723b722f5
## Why
Agents constantly mention files: stack traces, changed tests, docs, configs,
links, PRs. `termscope` lets you keep up without doing the little dance:
select text, copy, cd, paste, fix the path, add the line number.
If it's visible in the pane and exists in the repo, you can jump to it.
Termscope stays conservative:
- scans only the active pane's visible text
- verifies paths against the repo/worktree on disk
- preserves `file:line` targets
- falls back to a full repo picker when no visible file matches
- uses a session-modal Herdr popup, leaving the tiled pane layout untouched
## Requirements
- [Herdr](https://herdr.dev) `>= 0.7.4` or tmux
- Python `>= 3.10`
- [`fd`](https://github.com/sharkdp/fd)
- [Homebrew](https://brew.sh) when a Herdr plugin install needs to add or upgrade Television
- [Television](https://alexpasmantier.github.io/television/) `>= 0.15` (provisioned automatically when needed)
- [`bat`](https://github.com/sharkdp/bat) is optional for syntax-highlighted previews
- `nvim` for the default file-open action
- `open` on macOS or `xdg-open` on Linux for default-app opens
Native Windows is not claimed yet. WSL may work through `wslview` when your WSL
environment provides it.
## Install as a Herdr plugin
```bash
herdr plugin install iurysza/termscope
```
The install includes a visible build step that installs or upgrades Television
through Homebrew when `tv` is missing or older than `0.15`. It never installs
Homebrew itself; a missing Homebrew installation aborts cleanly before the
plugin is registered.
For local development (`plugin link` does not run install-time build steps):
```bash
git clone https://github.com/iurysza/termscope.git
cd termscope
./scripts/install-dependencies.sh
herdr plugin link "$PWD"
```
Verify Herdr sees the actions:
```bash
herdr plugin action list --plugin termscope
```
## Bind keys in Herdr
Herdr plugins register actions; keybindings still live in your
`~/.config/herdr/config.toml`.
```toml
[[keys.command]]
key = "ctrl+shift+a"
type = "plugin_action"
command = "termscope.open"
description = "visible-screen file picker"
[[keys.command]]
key = "ctrl+e"
type = "plugin_action"
command = "termscope.open-links"
description = "visible-screen link picker"
```
Reload config:
```bash
herdr server reload-config
```
## Use it
| Key | Action |
| --- | --- |
| `Ctrl-Shift-A` | Open visible file picker |
| `Ctrl-E` | Open visible link picker |
File picker controls:
| Key | Action |
| --- | --- |
| `Enter` | Open in a new Neovim split beside the source pane |
| `Ctrl-O` | Open with the default app |
| `Ctrl-Y` | Agent pane: send `/plannotator-annotate `; shell pane: run `plannotator annotate ` |
| `Ctrl-S` | Toggle appearance order / alphabetical sort |
Link picker controls:
| Key | Action |
| --- | --- |
| `Enter` | Open URL in the browser/default opener |
| `Ctrl-Y` | Copy URL to clipboard |
| `Ctrl-S` | Toggle appearance order / alphabetical sort |
## tmux usage
Herdr is the main plugin target, but the same picker works in tmux.
```tmux
set -g @termscope "/path/to/termscope/termscope"
bind-key -n C-S-a run-shell "tmux display-popup -E -w 80% -h 60% '#{@termscope} pick --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}'"
bind-key -n C-e run-shell "tmux display-popup -E -w 80% -h 60% '#{@termscope} links --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}'"
bind-key -T copy-mode-vi C-S-a run-shell "tmux display-popup -E -w 80% -h 60% '#{@termscope} pick --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}'"
bind-key -T copy-mode-vi C-e run-shell "tmux display-popup -E -w 80% -h 60% '#{@termscope} links --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}'"
bind-key -T copy-mode-vi 'o' send -F -X copy-pipe-and-cancel "#{@termscope} open --mode nvim --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}"
bind-key -T copy-mode-vi 'O' send -F -X copy-pipe-and-cancel "#{@termscope} open --mode default --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}"
bind-key -T copy-mode-vi P run-shell "tmux display-popup -E -w 80% -h 60% '#{@termscope} pick --pane-path #{q:pane_current_path} --pane-id #{q:pane_id}'"
```
In tmux copy-mode these bindings preserve the scrolled viewport instead of
jumping back to the live bottom of the pane.
## Configuration
| Environment variable | Purpose |
| --- | --- |
| `TERMSCOPE_OPENER` | Override default opener, e.g. `open -a Zen` or `open -a Firefox` |
| `TERMSCOPE_SORT` | Default sort mode: `appearance` or `alpha` |
| `TERMSCOPE_LOG` | Path to the JSON event log |
| `TERMSCOPE_DEBUG_DIR` | Directory for per-run debug dumps |
Examples:
```bash
export TERMSCOPE_OPENER='open -a Zen'
export TERMSCOPE_SORT=alpha
```
## Dry run / debug
See what the scanner would offer without opening Television:
```bash
./termscope scan --pane-path "$PWD" --pane-id "$HERDR_PANE_ID" --multiplexer herdr
```
Enable debug dumps:
```bash
export TERMSCOPE_DEBUG_DIR=/tmp/termscope-debug
```
Each run writes the captured screen, indexed files, candidates, and final
selection decision.
## How it works
Herdr plugin actions run without a TTY, so `termscope.open` first opens an
`80% × 60%` session-modal popup. The popup inherits the source pane id/cwd,
captures visible text with `herdr pane read --source visible`, scans the repo
with `fd`, and runs Television. Two bundled channels let `Ctrl-S` cycle between
appearance and alphabetical order. File previews use `bat` when available and a
built-in text preview otherwise.
When you choose a file, Termscope asks Herdr to split beside the source pane and
runs `nvim +line path`. For URLs, it uses the default opener unless
`TERMSCOPE_OPENER` is set.
## Development
```bash
python3 -m py_compile termscope termscope_herdr.py
python3 -m unittest discover -s tests
herdr plugin link "$PWD"
herdr plugin action invoke termscope.open
```
The repo intentionally has no package manager or build step. Herdr installs it
by cloning the repo and reading `herdr-plugin.toml`.
## License
[MIT](LICENSE) © iury souza