Ovvi

Future work

Designs for parts the app does not have yet, and what it leaves out on purpose

The pages in this section keep the designs for parts that are not built yet, so the work starts from them when it is picked up. Each page says at the top what of it is built. Smaller deferrals are marked "Simpler choice" on their own pages.

The designs follow the rules of the app as it is built: herdr is the source of truth, the app reaches each machine through run (over the relay on a remote machine) (Running commands), and the app never calls herdr's focus methods. A design gets decision numbers on the Decisions page when it is built.

Smaller items

  • herdr's machines in Add Machine. When herdr is on the Mac, the dialog lists the targets of the enabled entries of herdr machine list --json ({id, label, target, session, enabled}) that are not in the app's list, each with a checkbox. While the app's list is empty, they start checked. The app never writes herdr's list (The machine list).

  • Image paste. ⌘V with an image and no text on the clipboard, in a terminal or agent card or the chat reply box: the app encodes it as PNG, copies it to the pane's machine as a dropped file is copied (Exec.upload, at most 16 MB, over the relay on a remote machine; Drag and drop), and pastes the copy's path (or adds it to the chat draft). Agents such as Claude Code read the image from the path. A larger image shows "Image too large to paste". herdr's own remote client, uHerdr, collie, termote and roamgate do the same. Rejected: image bytes through the terminal (herdr's stream and agents do not take them); a server helper.

  • Reorder the machines in the machine menu.

  • herdr inside the app (herdr-core), so the user never installs herdr or needs to know about it: no mention of herdr anywhere in the app's UI.

  • Releases and updates: CI builds a notarized Developer ID .dmg and .app on a version tag and uploads them to GitHub (signed ad hoc now: Platform), and the app checks for updates and tells the user.

  • Anonymous telemetry: daily users, error reports and other usage numbers, sent to a hosted analytics service.

  • Richer agent notifications than the needs-you and finished banners (Status).

  • Local Network privacy (macOS 15 and later). An ssh that the app starts counts as the app, so a target on the local network fails with "No route to host" today. The plan: the app declares NSLocalNetworkUsageDescription, resolves the target with ssh -G, and opens an NWConnection to a local address before the first SSH connection, so the system asks once. If the user says no, the page shows "Allow Local Network access for Ovvi in System Settings › Privacy & Security". Tailscale addresses are not affected.

  • VoiceOver reads the terminal. A terminal card gives VoiceOver its screen text, read with pane.read {source:"visible", format:"text"} when VoiceOver asks for it, and announces new output politely (it does not interrupt speech). Today the card gives only its grid size.

  • tmux as one more implementation of the Multiplexer interface, after Rex. Research: tmux.md.

  • Jump to the next agent that needs you with one key, in the sidebar's order. It selects space, tab and card in the app and never calls herdr's focus methods.

  • Faster git state: stat HEAD, index and the branch ref each second, and run git status only on a change or an agent status change (Git status). On a remote machine each stat is a round trip, so batch them in one stat run, or keep today's poll there.

  • The rest of the browser pane (Browser):

    • Find in the page: ⌘F, with WKWebView's find in the same find bar.
    • "Open in Browser" as the palette's top row when the query is an address.
    • The Web Inspector button lit (the accent on an accent circle at 0.07, as Zoom's Restore) while the inspector shows.
    • An "Open :‹port›" chip on a terminal card whose screen shows a localhost address.
    • Refresh, and the safe list in the Settings window, where the user can edit it.
    • "‹machine› does not allow port forwarding": an ssh -W probe after a refusal tells it from a closed port.
  • The rest of the default plugins and of the plugin system: their Not built lists (default plugins, plugins), and a plugin setting with a value per machine (the browser's network is one value for new cards on every machine).

  • The rest of the chat view (Chat view):

    • A host for the pill card: the chat at 360 pt, built when the floating pills land.
    • Subagent rows: Claude Code's and Codex's subagents, OpenCode's child sessions.
    • OpenCode 2.x, with its shared service and /api/* routes.
    • A Codex fork with its parent's lines up to the fork (forked_from_ordinal_exclusive). Today it shows only its own lines.
  • Agents use a browser card. An agent can open a browser card and change its address (ovvi open browser), nothing more. An agent that needs to drive a page runs its own browser on its machine (Playwright, chrome-devtools-mcp). WKWebView has no automation protocol. A later design lets an agent ask the app, through the ovvi command (Agent control), to read, run script in or capture one browser card it is allowed to. It needs its own consent design.

  • Terminal keys to check against libghostty (herdr-gpui's defaults, research): ⇧↩ sent as Esc and CR, because herdr sends a bare CR for Shift-Enter to a program without kitty keys, which submits an agent's prompt. Option as Alt "auto": the left Option key is Alt on US and ABC layouts, and the right one types accents. First check what the app sends today.

  • Back and Forward through the panes the keyboard visited, and ⇧⌘T to reopen the last closed tab (a new tab in its folder: its programs ended with it). Back and Forward need their own keys: ⌘[ and ⌘] step panes, and ⌃- ⌃⇧- are a plugin card's.

  • herdr plugin values. herdr's TUI shows what herdr plugins report: agents[].tokens, state_labels and tab_bar_right. The app shows them too, read only, where herdr's TUI does. It never writes herdr's shared config.toml.

  • A remote home shown as ~ in card headers, and Go to Directory on a remote machine.

  • A bigger server helper. The relay already carries every run of a remote machine on one SSH session (The SSH connection). A helper of our own with more to do (a file watcher, a port forwarder) would sit behind the same run call. Build it only when one of these is real:

    1. Latency: a plugin needs many small calls (a file tree, search), and users on slow links feel it.
    2. File watching: a plugin needs pushed file changes, not a check every 2 s.
    3. AllowTcpForwarding no: a server refuses the port forwards that browser panes use.
    4. Windows servers: herdr supports them; the sh envelope does not.

    Plugins, labels and state files stay the same when it comes. Research: plugins.md.

Waiting on herdr

  • herdr's popup in a floating window. On herdr 0.9.5, plugin.pane.open with placement: "popup" answers only ok. The popup's terminal runs in the server, but it has no pane or terminal id in the reply, the snapshot or pane.list, and opening or closing it (popup.close) sends no event. The plugin_pane_opened reply comes only for the other placements, which are normal panes. The ask: the popup (its terminal id and size) in session.snapshot, events when it opens and closes, and a close by id (popup.close takes no parameters). Ovvi then streams it by that id in a floating window, as it does a floated pane.
  • Panes started with a command after a cold restart come back as plain shells, with their label. The ask: restore them with their launch_argv, opt-in (discussion #1367). Web and plugin panes work anyway, because the label is the truth (Labels and instance ids).
  • Clipboard writes on the terminal stream. herdr 0.9.5 gives a pane's OSC 52 write (ServerMessage::Clipboard) only to its foreground TUI client, and terminal session control prints only frames and the close. The ask: a terminal.clipboard event on the control stream, sent to the client that streams the pane. Then the app puts it on the clipboard, and every program's copy works from a remote machine, as pi-hkandala's copy does through ovvi copy (Scrolling, queries and links).
  • Named keys on the terminal stream. The ask: herdr accepts named keys on terminal.input ({"type":"terminal.input","keys":["up"]}), encoded as pane.send_keys does. Then all input takes one path, with no request per key burst, which matters over SSH (Terminal plane).
  • Claude Code's transcript path. herdr's Claude hook sends transcript_path, but herdr 0.9.5 keeps a path in agent_session only for pi and omp. The ask: keep it for Claude Code. Then the chat view could take the path from herdr instead of its own SessionStart hook.
  • Blocked for menus, and forks. herdr 0.9.5 reports idle while an agent shows a picker (Claude Code, Codex and opencode model and session pickers) or a pi extension dialog, and keeps the old agent_session after Claude Code's /branch and Codex's /fork. The ask: blocked for those, and the new session after a fork. Then the chat view needs no screen check for Codex before a send.
  • OSC 7501, the Program Status Protocol: a terminal escape sequence that a program sends to report its status (spec). herdr does not support it yet. Draft PR #5172 adds program_status to pane.get and pane.list, and a change to it alone sends no event. Once herdr ships it, the app shows its message on needs-you and finished rows and in notifications, and says "failed" for error. Another multiplexer may report it through its own API (Rex).

Left out on purpose

  • Tearing a tab off into a new window: a tab belongs to its herdr space, and a window shows pages, not single tabs.
  • Key sequences and custom shortcuts: macOS menus hold the shortcuts.
  • Traffic lights inside the tab bar: needs private API (setCustomTitlebarHeight:).
  • Jump to prompt: needs OSC 133 marks, and herdr's frames carry none.
  • A font size per pane (one text size for the app), paste confirmation (small; on request), an installer for agent integrations (herdr's own installer writes the agents' config files; it belongs with the Settings window).
  • Many themes and a theme editor: the user wants only light, dark, Glass and Classic. A compact density: the user dropped it.
  • A menu bar status item: the floating pills would cover it.
  • A diagnostics window: not interface work.
  • Decorations with a GPU cost (Rex's melt transition, selection pulse).
  • Rex's theme, material or decompiled files in the repo: Ovvi copies looks by measuring, never Rex's files or icon art.

On this page