{"id":51440943,"url":"https://github.com/vestaterm/Vesta","last_synced_at":"2026-07-07T22:00:48.511Z","repository":{"id":367558536,"uuid":"1279225546","full_name":"vestaterm/Vesta","owner":"vestaterm","description":"A native macOS terminal for running AI coding agents in parallel — built on real libghostty, with persistent tmux-style sessions and a scriptable Lua/CLI control plane.","archived":false,"fork":false,"pushed_at":"2026-06-30T18:09:03.000Z","size":7545,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-30T20:09:12.727Z","etag":null,"topics":["ai-agents","appkit","developer-tools","ghostty","lua","macos","multiplexer","pty","swift","terminal","terminal-emulator","tmux"],"latest_commit_sha":null,"homepage":"https://vestaterm.github.io/vesta-site/","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/vestaterm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/roadmap.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-24T13:42:04.000Z","updated_at":"2026-06-30T18:09:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/vestaterm/Vesta","commit_stats":null,"previous_names":["notnaki/halo","notnaki/vesta","vestaterm/vesta"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/vestaterm/Vesta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestaterm%2FVesta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestaterm%2FVesta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestaterm%2FVesta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestaterm%2FVesta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/vestaterm","download_url":"https://codeload.github.com/vestaterm/Vesta/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/vestaterm%2FVesta/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35243953,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-07T02:00:07.222Z","response_time":90,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","appkit","developer-tools","ghostty","lua","macos","multiplexer","pty","swift","terminal","terminal-emulator","tmux"],"created_at":"2026-07-05T12:00:25.873Z","updated_at":"2026-07-07T22:00:48.504Z","avatar_url":"https://github.com/vestaterm.png","language":"C","funding_links":[],"categories":["ターミナルアプリ","Terminal"],"sub_categories":["データベース","Text"],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/vesta-icon.png\" width=\"120\" alt=\"Vesta icon\"\u003e\n\u003c/p\u003e\n\n\u003ch1 align=\"center\"\u003eVesta\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003eA native macOS terminal for running AI coding agents in parallel —\u003cbr\u003ebuilt on real \u003ca href=\"https://ghostty.org\"\u003elibghostty\u003c/a\u003e, driven by a scriptable CLI.\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/vestaterm/Vesta/releases/latest\"\u003e\u003cb\u003eDownload\u003c/b\u003e\u003c/a\u003e ·\n  \u003ca href=\"https://vestaterm.github.io/vesta-site/\"\u003eWebsite\u003c/a\u003e ·\n  \u003ca href=\"https://vestaterm.github.io/vesta-site/docs.html\"\u003eDocs\u003c/a\u003e ·\n  \u003ca href=\"https://vestaterm.github.io/vesta-site/assets/vesta-demo.mp4\"\u003e▶\u0026nbsp;Watch\u0026nbsp;the\u0026nbsp;tour\u003c/a\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/hero.png\" width=\"840\" alt=\"Two Claude Code agents running side by side in Vesta, with the project sidebar showing 'halo · 2 panes'\"\u003e\n\u003c/p\u003e\n\n---\n\nVesta is a Swift/AppKit terminal that links **GhosttyKit.xcframework** (it is not\na Ghostty fork). It renders with Ghostty's Metal engine, reads your existing\n`~/.config/ghostty/config` as-is, and adds a project sidebar, tmux-style splits,\nand an agent-control CLI on top.\n\n## Highlights\n\n- **Real libghostty** — Ghostty's Metal renderer, your ghostty config and\n  theme, zero reimplemented terminal logic.\n- **Persistent sessions (tmux-style)** — shells survive Vesta quitting and\n  reattach cleanly. A small daemon (`vestad`) holds the PTYs; panes connect\n  through a relay (`vesta-attach`). Prefix-key mode for tmux muscle memory.\n  Restore is lazy: at launch only the visible session reattaches; the rest\n  stay listed in the sidebar and attach instantly on first click, so a big\n  saved workspace opens fast. Until a restored session is first activated it\n  won't ring the attention dot (its shell keeps running under the daemon\n  regardless, and plugin `pane-output` taps still work).\n- **Projects → sessions sidebar** — vertical, drag-resizable. Each project owns\n  sessions; rename / recolor / remove from the right-click menu.\n- **Native splits** — `⌘D` / `⌘⇧D`, click-to-focus, zoom, drag dividers.\n- **Command palette** — `⌘⇧P` opens a searchable list of every action (splits,\n  sessions, browser pane, settings…) plus your plugins' `vesta.command` entries.\n- **Scriptable** — the `vesta` CLI drives and reads the live UI over a Unix\n  socket, so agents can orchestrate it.\n- **Notifications** — `vesta.notify` from a plugin shows a stacking in-app toast,\n  records it in a titlebar **bell** (history persists across restarts), and posts\n  a macOS Notification Center banner when Vesta is backgrounded (or when forced).\n- **Self-updating** — when a newer release exists, a badge appears at the sidebar\n  bottom; click it to download, install (in place), and relaunch — no manual DMG.\n- **Pick your app icon** — **Settings ▸ App Icon** swaps between a clean white\n  flame, a pink one, and ten progressively \"corrupted\" stages (or click the icon\n  in the About panel to cycle them). The choice is written onto the `.app` bundle,\n  so it sticks in Finder/Dock across quits and survives in-place updates.\n- **Everything from your config** — colors, fonts, sidebar width, divider width\n  are all `vesta-*` keys in the same ghostty config file. Empty config = sane\n  defaults.\n\n## Build \u0026 run\n\nNo setup needed — `swift build` fetches the prebuilt GhosttyKit framework\n(libghostty) automatically via a checksum-verified release asset.\n\n```sh\nswift build                                       # auto-fetches GhosttyKit on first build\n.build/arm64-apple-macosx/debug/vesta            # run the app (dev)\nswift run vesta selfcheck                          # pure-logic checks\n./install.sh                                      # copy vesta + vestad + vesta-attach → /usr/local/bin (CLI)\n\n./make-app.sh                                     # build Vesta.app (double-clickable, logo icon)\nopen Vesta.app                                     # launch the bundle\n```\n\n\u003e The raw debug binary is bundle-less and dies if its launching shell exits (use\n\u003e `nohup .build/.../vesta \u0026 disown`). **`./make-app.sh`** packages a proper\n\u003e `Vesta.app` — logo dock icon, \"Vesta\" menu, double-click launch, detached\n\u003e lifetime. The binary is self-contained (ghostty is statically linked).\n\n## The `vesta` CLI\n\nDrives the running app over `~/Library/Application Support/vesta/control.sock`.\n`vesta help` is authoritative; the common verbs:\n\n```sh\nvesta help                       # list every verb + config key\nvesta open \u003cpath\u003e                # new session at \u003cpath\u003e\nvesta split -v | -h              # split the focused pane (side-by-side / stacked)\nvesta new-pane --cwd \u003cpath\u003e      # new pane in a dir\nvesta focus \u003cid\u003e | vesta focus next\nvesta zoom                       # toggle zoom on the focused pane\nvesta close                      # close the focused pane\nvesta send-keys \u003ctarget\u003e \u003ctext\u003e  # type into a pane + run it (target = pane id or \"focused\"; --no-enter to skip the Return)\nvesta send-keys --all|--session \u003cP.S\u003e|--project \u003cname\u003e \u003ctext\u003e   # broadcast: focused session's panes / session P.S / all of a project (reply: pane count)\nvesta capture                    # dump the focused pane's screen\nvesta pane status \u003cpaneID\u003e       # JSON for one pane: cwd, title, alive, attention\nvesta list                       # the focused session's panes (+ tab index/count)\nvesta tab new|next|prev|close    # tab control\nvesta sessions [--json] [--project \u003cname\u003e]   # list sessions; --json for structured records (id, name, cwd, panes, active/attention; --project implies --json)\nvesta kill \u003cid\u003e                  # end a session's shell (by paneID)\nvesta notify [--desktop] [--title \u003ct\u003e] \u003cmsg\u003e   # toast + bell; desktop banner when backgrounded (--desktop forces)\n```\n\n## Multiplexer \u0026 sessions\n\nShells run under a small daemon (`vestad`), not the app, so they **survive Vesta\nquitting** and **reattach cleanly**. The daemon owns one `forkpty`'d shell per\npane and keeps the last ~256 KB of its raw output; on attach it replays those\nbytes and ghostty re-renders them — colors, cursor, full-screen apps and all\n(no separate screen model, so nothing to garble). On by default; set\n`vesta-persist = false` for plain non-persistent shells.\n\nWhat you get:\n\n- **Survive quit** — `⌘Q`, reopen Vesta: panes come back with their shells and\n  recent output.\n- **Close ends the shell** — `⌘W` closes the focused pane (a non-last pane\n  detaches; the last pane closes **and kills** its session). `⌘⇧W` closes and\n  kills the session. Shells survive only across window-close / `⌘Q` quit, and\n  reattach on relaunch. To keep a shell but drop the pane, prefix-`d` (detach).\n- **Prefix mode** — tmux muscle memory. Press the prefix (`ctrl+b` by default,\n  `vesta-prefix`), then a key (table below). Empty `vesta-prefix` disables it.\n- **Explicit kill** — prefix-`x`, or `vesta kill \u003cid\u003e` — when you actually mean\n  to end the shell.\n\n### Verify it works\n\n```sh\n# 1. survive quit\n#    in a pane:   echo i-was-here \u0026\u0026 date\n#    ⌘Q, reopen Vesta.app → the pane shows that output again.\n\n# 2. detached sessions survive\n#    close the window (not ⌘⇧W) → its shells keep running; relaunch → they reattach.\n#    or prefix-d a pane to detach it (shell lives on under vestad).\n\n# 3. from the CLI, watch the daemon hold sessions\nvesta sessions            # lists live + detached sessions with attach counts\nvesta kill \u003cid\u003e           # ends one for real\n```\n\nIf a pane ever says \"daemon protocol … update Vesta\", an **old `vestad` from a\nprevious build** is still running (`pkill -f vestad`, then relaunch) — the\ndaemon is single-instance per user.\n\n### Prefix keytable (after `ctrl+b`)\n\n| Key | Action | Key | Action |\n|-----|--------|-----|--------|\n| `%` | split vertical | `c` | new session |\n| `\"` | split horizontal | `n` / `p` | next / prev session |\n| `h j k l` / arrows | focus pane | `,` | rename session |\n| `z` | zoom pane | `d` | detach pane |\n| `x` | kill shell |  |  |\n\nOverride bindings with `vesta-prefix-bind = key:action, …` in your ghostty config.\n\n## Configuration\n\nVesta reads `vesta-*` keys from your ghostty config (libghostty ignores them).\nStandard ghostty keys (`theme`, `background`, `foreground`, `cursor-color`,\n`palette = N=#hex`) apply live. Every `vesta-*` default matches the built-in\nlook, so an untouched config changes nothing.\n\n| Key | Default | Meaning |\n|-----|---------|---------|\n| `vesta-accent` | theme accent | accent color (rings, dots, focus ticks) |\n| `vesta-surface` | theme background | base surface color |\n| `vesta-sidebar-width` | 224 | sidebar open width (px) |\n| `vesta-font-family` | GeistMono | chrome label font |\n| `vesta-font-mono` | MartianMono | mono font |\n| `vesta-font-size` | 13 | chrome font size |\n| `vesta-divider-width` | 8 | split divider grab width (1px hairline drawn) |\n| `vesta-projects` | — | comma-separated project paths to preload |\n| `vesta-persist` | true | run shells under `vestad` (survive quit); `false` = plain shells |\n| `vesta-persist-scrollback` | false | mirror scrollback to disk so it survives a daemon restart. **Off by default** — terminal output can contain secrets (see [SECURITY.md](SECURITY.md)) |\n| `vesta-prefix` | ctrl+b | prefix key for tmux-style mode; empty = disabled |\n| `vesta-prefix-bind` | — | override prefix bindings: `key:action, …` |\n\n## Keybindings\n\n| Keys | Action |\n|------|--------|\n| `⌘D` / `⌘⇧D` | split vertical / horizontal |\n| `⌘W` / `⌘⇧W` | close pane / close session |\n| `⌘T` | new session in active project (cwd = project dir) |\n| `⌘]` | focus next pane |\n| `⌘{` / `⌘}` | previous / next session |\n| `⌘1`–`⌘9` | select session N |\n| `⌘B` | toggle sidebar |\n| `⌘⇧P` | command palette (search + run any action or plugin command) |\n| `ctrl+b` then a key | prefix mode (see Multiplexer \u0026 sessions) |\n\nClick a pane to focus it; click a project to expand it; right-click a project\nto rename / recolor / remove it. `⌘W` closes the focused pane; `⌘⇧W` closes\n**and kills** its session — see Multiplexer \u0026 sessions.\n\n## Architecture\n\n- `Sources/Vesta/Ghostty/` — libghostty init, config sync, runtime callbacks.\n- `TerminalPane.swift` — a ghostty surface (input / IME / mouse / resize / cwd / title).\n- `PaneTree.swift` — tmux-style splits as nested `NSSplitView`s.\n- `Tabs.swift` — the `Workspace` model: projects own sessions.\n- `Chrome.swift` — window, titlebar, sidebar rendering.\n- `Control.swift` — the `vesta` CLI + socket server.\n- `GhosttyConfig.swift` — `Theme` + `VestaConfig` (the `vesta-*` keys).\n- `Git.swift` — branch / status, shelled out off-main.\n- `PrefixMode.swift` — tmux-style prefix mode.\n- `Sources/vestad/` — the session daemon: one `forkpty`'d shell per pane + a raw\n  output ring, replayed on attach. No terminal parsing (ghostty does that).\n- `Sources/vesta-attach/` — the per-pane relay ghostty spawns as its command;\n  a dumb byte pump between the pane and the daemon over a `0600` unix socket.\n- `Sources/VestaMux/` — shared wire protocol (`MuxProtocol`) + paths (`MuxPaths`).\n\n## Roadmap\n\nDesigns live in `docs/superpowers/specs/`. Shipped: **persistent sessions**\n(`2026-06-25-mux-rawring-rewrite.md`) — `vestad`/`vesta-attach` raw-ring\nmultiplexer, prefix mode. Deferred there: mirroring (one session in two panes),\nremote attach (`vesta attach ssh://`), and inline-image replay across detach.\n(Disk-spill scrollback later shipped as `vesta-persist-scrollback`.) Also in flight: **cmux parity**\n(`2026-06-22-cmux-parity-design.md`) — worktree-isolated sessions, attention\nrings, richer sidebar, embedded browser pane.\n\n## Self-checks\n\n```sh\n.build/arm64-apple-macosx/debug/vesta selfcheck   # config, control, git, workspace, chrome\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvestaterm%2FVesta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvestaterm%2FVesta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvestaterm%2FVesta/lists"}