diff --git a/docs/integrations/horizon.md b/docs/integrations/horizon.md new file mode 100644 index 00000000..e571b3e5 --- /dev/null +++ b/docs/integrations/horizon.md @@ -0,0 +1,89 @@ +# Horizon Integration Analysis + +Research note for [issue #389 — "Подумать об интеграции Horizon в проект"](https://github.com/ProverCoderAI/docker-git/issues/389). + +The issue asks the team to *think about* integrating [Horizon](https://github.com/peters/horizon) into docker-git. This document captures that evaluation: what Horizon is, how it overlaps with docker-git, whether a direct integration is feasible today, and which concrete options are worth pursuing. It is a decision document, not an implementation. + +## What Horizon Is + +Horizon is a GPU-accelerated "terminal board" that places every terminal session on an infinite 2D canvas. Sessions live as panels that can be placed, resized, grouped into color-coded workspaces, and auto-arranged (rows / columns / grid). A minimap keeps the user oriented, and canvas layout, scroll positions, and terminal history are restored across restarts. + +Verified facts (from the upstream repository, June 2026): + +| Property | Value | +| --- | --- | +| Repository | https://github.com/peters/horizon | +| Author | `peters` | +| Language | Rust (Edition 2024) | +| License | MIT | +| UI / rendering | `egui` (immediate-mode UI) on `wgpu` (Vulkan / Metal / DX12 / OpenGL) | +| Terminal engine | `alacritty_terminal` | +| Distribution | Desktop binaries — Linux x64, macOS arm64/x64, Windows x64 (Homebrew, WinGet, Snap Store, direct download) | +| Configuration | `~/.horizon/config.yaml` (workspaces, panel presets, shortcuts, feature flags, theme) | +| AI integrations | First-class launchers for Claude Code, Codex, OpenCode, Gemini CLI, KiloCode, plus a token-usage dashboard | +| Web / remote mode | **None** — desktop-only, no embedded HTTP API or headless mode documented | + +Sources: +- Upstream README — https://github.com/peters/horizon +- Show HN discussion — https://news.ycombinator.com/item?id=47416227 +- Original issue reference (Telegram) — https://t.me/open_source_friend/5669 + +## How It Overlaps With docker-git + +docker-git and Horizon solve adjacent problems, which is why the integration idea is attractive: + +- **Both are terminal-session managers.** docker-git already exposes per-project terminal sessions over the web (`packages/terminal`, `packages/api/src/services/terminal-sessions.ts`, `pty-bridge.ts`) with reconnect, inline images, mobile controls, copy-selection, and a task manager. +- **Both target AI-agent workflows.** docker-git's `--auto` flow runs Claude / Codex / Gemini / Grok inside per-issue Docker environments; Horizon ships first-class launchers for the same agent CLIs. +- **Both already overlap on "GPU".** docker-git has GPU compose overlays (`docker-compose.gpu.yml`, `docker-compose.api.gpu.yml`) and a GPU create-flow choice (`menu-create-navigation.ts`), so a GPU-accelerated companion is not foreign to the project. + +The key conceptual gap Horizon fills is **spatial organization**: docker-git lists terminal sessions in a panel/tab layout, while Horizon arranges them on an infinite canvas with workspaces and a minimap. + +## Feasibility: The Hard Constraints + +A direct "embed Horizon into the docker-git web UI" integration is **not feasible today**, for architectural reasons: + +1. **Horizon is desktop-only.** It renders through `wgpu`/`egui` into a native window. There is no web build, no headless mode, and no embeddable view. docker-git's primary surface is a browser UI (`bun run docker-git -- browser`) served to LAN/remote devices. A native GPU window cannot be served to a browser the way the existing React terminal panels are. +2. **No control API or protocol.** Horizon is configured through a static `~/.horizon/config.yaml` and driven by its own UI. It exposes no HTTP/tRPC/WebSocket surface that docker-git could proxy — unlike Skiller, whose tRPC backend docker-git proxies per session (see [`skiller.md`](./skiller.md)). +3. **Session model mismatch.** Horizon owns its own PTYs through `alacritty_terminal` and persists them locally. docker-git's sessions are PTYs bridged from inside per-project Docker containers (`pty-bridge.ts`). Horizon has no concept of "attach to a PTY that already lives in a remote container," so it cannot natively front docker-git's container sessions. +4. **Runtime stack divergence.** Horizon is a Rust/`wgpu` binary; docker-git is a Bun + TypeScript + Effect-TS workspace with a strict Functional-Core/Imperative-Shell discipline (`CLAUDE.md`). Vendoring Rust GPU code into this workspace adds a toolchain and a maintenance surface unrelated to the rest of the project. + +The Skiller integration worked precisely because Skiller is an Electron app with a tRPC backend that docker-git can launch and proxy. Horizon offers neither of those seams. + +## Integration Options + +Ordered from lowest to highest cost. None require committing to a direction in this PR — they are the menu for a follow-up decision. + +### Option A — Document it as a complementary desktop client (recommended first step) + +Treat Horizon as an *external* desktop board that a developer runs alongside docker-git, not something docker-git embeds. The two already share agent CLIs and SSH-based access. docker-git already advertises per-session SSH endpoints (`/ssh/session/:sessionId`); Horizon discovers hosts from SSH config and Tailscale. The lowest-cost, highest-confidence move is to make docker-git's per-project containers easy to add as Horizon panels via SSH, and document that workflow. + +- Cost: low (docs + verifying the SSH path). +- Risk: low. No new runtime, no vendored code. +- Payoff: real today for users who already run a desktop. + +### Option B — Borrow the UX, not the binary + +The genuinely valuable, web-deliverable part of Horizon is its **interaction model**: an infinite canvas of terminal panels, color-coded workspaces, auto-arrange (rows/columns/grid), a minimap, and restored layout. docker-git already owns its terminal panels in React (`packages/terminal/src/web`). A canvas/workspace layout *for docker-git's existing sessions* could be built natively in the web UI, reusing docker-git's own PTY bridge, without adopting Horizon's Rust stack. + +- Cost: medium-to-high (a real frontend feature). +- Risk: medium. Self-contained; no upstream coupling. +- Payoff: brings the headline benefit (spatial session management) to docker-git's actual web users. +- Note: this is "inspired by Horizon," not "integrating Horizon." It should be scoped as its own issue if pursued. + +### Option C — Submodule + launcher (the Skiller pattern) — not currently viable + +The Skiller model (pin as a `third_party` submodule, launch as a separate process, proxy its backend per session — see [`skiller.md`](./skiller.md)) does not transfer, because Horizon has no proxiable backend and no web view. Even launched, its native GPU window cannot be surfaced in docker-git's browser UI. Revisit only if upstream adds a headless/remote/web mode. + +## Recommendation + +1. **Do not embed or vendor Horizon now.** The desktop-only, API-less, Rust/`wgpu` design has no seam compatible with docker-git's web-served, container-bridged session model. +2. **Adopt Option A** as the immediate, low-risk step: position Horizon as a complementary external client and document the SSH-based workflow for adding docker-git project containers as Horizon panels. +3. **Track Option B separately.** The infinite-canvas + workspaces + minimap UX is the part worth bringing to docker-git's web UI, built natively on the existing terminal panels. It deserves its own scoped issue rather than being folded into "integrate Horizon." +4. **Re-evaluate Option C** only if Horizon upstream ships a headless or web/remote mode that exposes a controllable session API. + +## Watch List (re-evaluate triggers) + +Revisit this analysis if any of the following land upstream: +- Horizon adds a headless mode, web build, or remote-rendering surface. +- Horizon exposes a control API (HTTP/WebSocket/tRPC) for creating and attaching sessions. +- Horizon supports attaching to an externally-owned PTY (e.g. an SSH or container-bridged session) instead of only spawning its own.