{"id":50428218,"url":"https://github.com/aeksco/lazarux","last_synced_at":"2026-05-31T12:01:26.990Z","repository":{"id":361505142,"uuid":"1254702831","full_name":"aeksco/lazarux","owner":"aeksco","description":"🧟‍♂️ A web GUI for editing tmux-resurrect session state","archived":false,"fork":false,"pushed_at":"2026-05-31T01:04:23.000Z","size":376,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-31T01:10:09.467Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://lazarux.vercel.app","language":"TypeScript","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/aeksco.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":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-30T22:46:09.000Z","updated_at":"2026-05-31T01:04:27.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/aeksco/lazarux","commit_stats":null,"previous_names":["aeksco/lazarux"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/aeksco/lazarux","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aeksco%2Flazarux","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aeksco%2Flazarux/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aeksco%2Flazarux/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aeksco%2Flazarux/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aeksco","download_url":"https://codeload.github.com/aeksco/lazarux/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aeksco%2Flazarux/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33730241,"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-05-31T02:00:06.040Z","response_time":95,"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":[],"created_at":"2026-05-31T12:01:26.173Z","updated_at":"2026-05-31T12:01:26.981Z","avatar_url":"https://github.com/aeksco.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Lazarux\n\n\u003e _Raise your tmux sessions from the dead._\n\nA web GUI for editing [tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect)\nsession state. Upload a `~/.tmux/resurrect/` save file, reshape your sessions,\nwindows, and panes visually, preview the result as a dummy terminal, and export\na `sessions.txt` you can restore — all in the browser, no backend.\n\nUseful when you want to reorganize a restored tmux workspace: rename sessions,\nsplit a giant session into several, reorder windows, move a window from one\nsession to another, or clean up after a messy restore.\n\n![Lazarux — the collapsible multi-session editor](./docs/app.png)\n\n## Why?\n\nI had accumulated *way* too many tmux sessions, windows, and panes — dozens of\nsessions, well over a hundred windows. Reorganizing all of that from inside tmux\nwas painful: `move-window`, `swap-window`, `move-pane`, renaming things one at a\ntime, juggling indexes, and constantly losing my place. There was no way to step\nback and see the whole layout, let alone drag things around.\n\nSince [**tmux-resurrect**](https://github.com/tmux-plugins/tmux-resurrect)\nalready persists my entire workspace to a plain text file under\n`~/.tmux/resurrect/`, the obvious move was to edit *that* instead of poking at a\nlive tmux server. Lazarux gives you a bird's-eye GUI over that save file —\ncollapse the noise, drag windows between sessions, reorder and reindex in bulk —\nthen export a `sessions.txt` you restore with `prefix + Ctrl-r`. Reorganizing a\nsprawling workspace goes from a tedious sequence of tmux commands to a few\nminutes of clicking and dragging.\n\n\u003e **Lazarux is specifically a tool for\n\u003e [tmux-resurrect](https://github.com/tmux-plugins/tmux-resurrect).** It reads and\n\u003e writes that plugin's save format — you'll want tmux-resurrect installed and a\n\u003e saved session (`prefix + Ctrl-s`) to get the most out of it.\n\n## Features\n\n- **Round-trips losslessly** — parsing a save file and re-exporting it (with no\n  edits) produces a byte-for-byte identical file.\n- **Multi-session editor** — collapsible session/window list; edit session names,\n  window names/flags/layout, and pane paths/commands/titles.\n- **Drag \u0026 drop** windows to reorder within a session or move them to another\n  (with viewport edge auto-scroll for long lists), or use the **Move** dialog.\n- **Reorder / reindex** — move sessions up/down; renumber a session's windows to\n  match their order (tmux restores windows by index, not file order).\n- **Terminal preview** — a dummy terminal that renders a session's active window\n  by parsing the tmux layout string into real pane rectangles, with a session\n  dropdown and a clickable tmux-style window bar.\n- **Autosave** — the current config is kept in `localStorage`, so a refresh\n  doesn't lose your work. A **Reset** button clears everything.\n- **Guards the two tmux footguns** (see below): session-name prefix collisions\n  and window names lost to `automatic-rename`.\n\n## Getting started\n\nRequires Node.js 18+ (developed on 24).\n\n```bash\nnpm install\nnpm run dev      # http://localhost:3000\n```\n\nBuild / run production:\n\n```bash\nnpm run build\nnpm run start\n```\n\n### Typical workflow\n\n1. **Upload** your latest save (`~/.tmux/resurrect/last` — copy it to `*.txt`),\n   or click **New file** to start from scratch.\n2. Edit sessions/windows/panes; check the **Preview** tab to sanity-check a\n   session's layout.\n3. **Export sessions.txt** and drop it back into `~/.tmux/resurrect/` (overwrite\n   the file `last` points to), then restore in tmux with `prefix + Ctrl-r`.\n\n## The two tmux footguns it guards against\n\n**1. Session-name prefix collisions.** tmux resolves a session target by exact\nmatch first, then by *prefix* — so `has-session -t \"automation\"` matches an existing\nsession `automation - home`. On restore, tmux-resurrect skips creating the shorter-named\nsession and merges its windows into the longer one. The app flags any session\nwhose name is a prefix of another, inline and in a banner.\n\n**2. Window names lost to `automatic-rename`.** If your tmux has\n`automatic-rename on` (the default), restored window names get immediately\noverwritten by each window's running command (`zsh`, `node`, …). The **Lock\nwindow names** option (on by default) writes `automatic_rename=off` for every\nwindow on export, so the names you set survive the restore regardless of your\nglobal tmux setting. (Equivalent to adding `set -g automatic-rename off` to your\n`~/.tmux.conf`.)\n\n## The data model\n\ntmux-resurrect's format is tab-separated lines (`pane`, `window`, `state`), with\nthe session name on every line and a single `state` line for the attached\nsession. The app parses this into a structured, JSON-friendly shape:\n\n```jsonc\n{\n  \"sessions\": [\n    {\n      \"name\": \"automation\",\n      \"windows\": [\n        {\n          \"index\": 1,\n          \"name\": \"scraper\",\n          \"active\": 1,\n          \"flags\": \"*\",\n          \"layout\": \"b9fe,187x52,0,0,1\",\n          \"automaticRename\": \"off\",\n          \"panes\": [\n            { \"index\": 1, \"title\": \"\", \"path\": \"/code/automation/scraper\",\n              \"active\": 1, \"command\": \"zsh\", \"fullCommand\": \"\" }\n          ]\n        }\n      ]\n    }\n  ],\n  \"activeSession\": \"automation\",\n  \"hasTrailingNewline\": true\n}\n```\n\ntmux-resurrect guards certain fields with a leading `:`; the parser strips it and\nthe serializer re-adds it, which is what makes the round-trip lossless.\n\n## Project structure\n\n```\nsrc/\n  app/\n    layout.tsx          Root layout + fonts\n    page.tsx            Toolbar, persistence, view switching (Editor/Preview/JSON)\n    globals.css         Theme tokens + Tailwind\n    components/\n      Editor.tsx        Session/window/pane editor (drag \u0026 drop, dialog)\n      Preview.tsx       Dummy terminal + tmux layout renderer\n  components/ui/        shadcn/ui primitives\n  lib/\n    types.ts            Shared types (ResurrectDoc, Session, TmuxWindow, Pane)\n    resurrect.ts        parse / serialize (pure, no DOM/fs)\n    model.ts            Factories + normalization helpers (pure)\n    utils.ts            cn() class-name helper\n```\n\n## Tech stack\n\n- Next.js (App Router)\n- React\n- TypeScript\n- Tailwind CSS v4\n- shadcn/ui (Radix).\n\n## License\n\nOpens source under the MIT License.\n\nBuilt with ❤️ by [aeksco](https://x.com/aeksco)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faeksco%2Flazarux","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faeksco%2Flazarux","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faeksco%2Flazarux/lists"}