{"id":49881385,"url":"https://github.com/kdnk/seiton","last_synced_at":"2026-05-15T14:37:11.728Z","repository":{"id":353775894,"uuid":"1220017380","full_name":"kdnk/seiton","owner":"kdnk","description":null,"archived":false,"fork":false,"pushed_at":"2026-05-03T06:56:51.000Z","size":865,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-03T08:26:39.770Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kdnk.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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-04-24T13:09:00.000Z","updated_at":"2026-05-03T06:56:56.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/kdnk/seiton","commit_stats":null,"previous_names":["kdnk/seiton"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/kdnk/seiton","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdnk%2Fseiton","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdnk%2Fseiton/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdnk%2Fseiton/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdnk%2Fseiton/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kdnk","download_url":"https://codeload.github.com/kdnk/seiton/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kdnk%2Fseiton/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33070211,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T11:35:32.926Z","status":"ssl_error","status_checked_at":"2026-05-15T11:35:31.362Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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-15T14:37:08.876Z","updated_at":"2026-05-15T14:37:11.711Z","avatar_url":"https://github.com/kdnk.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# seiton\n\nSeiton is an Electron app for managing GitButler branches as real tmux and Kitty work contexts.\n\nIt gives you one place to:\n\n- add and switch project directories\n- sync GitButler branches into managed tmux sessions and Kitty tabs\n- rename contexts across GitButler, tmux, and Kitty together\n- reorder projects and contexts with drag and drop\n- remove orphan tmux and Kitty state\n- inspect Codex panes per context and focus them directly\n\n## Requirements\n\n- macOS or Linux\n- `tmux`\n- `kitty` with remote control available\n- `but` (GitButler CLI)\n- Node.js\n\nSeiton assumes your working contexts are backed by:\n\n- GitButler branch state\n- tmux sessions\n- Kitty tabs\n\n## Install\n\n```bash\nnpm install\n```\n\n### macOS release note\n\nIf macOS shows `\"Seiton\" is damaged and can't be opened. You should move it to the Trash.`, remove the quarantine attribute from the installed app:\n\n```bash\nxattr -dr com.apple.quarantine /Applications/Seiton.app\n```\n\nRun this after moving `Seiton.app` into `/Applications`.\n\n## Run\n\nStart the app:\n\n```bash\nnpm run electron\n```\n\nStart the app with a specific initial project root:\n\n```bash\nnpm run electron:practice\n```\n\n`npm run dev` only starts the Vite renderer. Directory selection, tmux control, Kitty control, and GitButler integration require Electron.\n\n## Build\n\n```bash\nnpm run build\n```\n\nThis builds:\n\n- the renderer into `dist/`\n- the Electron main and preload bundles into `dist-electron/`\n- the CLI entrypoint into `dist-electron/cli.js`\n\n## Test\n\n```bash\nnpm test\n```\n\n## How Seiton works\n\nFor each GitButler branch in a registered project, Seiton manages:\n\n- one tmux session\n- one Kitty tab\n- one registry entry for ordering and persistence\n\nManaged names use this shape:\n\n```text\ns_\u003cproject-slug\u003e_\u003cbranch-key\u003e\n```\n\nExamples:\n\n- `git-butler-practice` + `seiton-parser-test` -\u003e `s_gbp_seiton-parser-test`\n- `seiton` + `kn-branch-1` -\u003e `s_seiton_kn-branch-1`\n\n## Current behavior\n\nSeiton currently supports:\n\n- project directory registration and switching\n- manual sync from GitButler branch state\n- context focus into Kitty, tmux session, and tmux pane\n- inline context rename\n- orphan cleanup\n- drag-and-drop ordering for projects and contexts\n- Settings panel for CLI command installation\n- agent pane display per context\n\n## Install the `seiton` command\n\nSeiton includes a small CLI used for Codex / Claude hooks and shell-based integration.\n\nYou can install it from the app:\n\n1. open Seiton in Electron\n2. open the `Settings` panel\n3. use `Install Command`\n\nSeiton installs a user-level symlink:\n\n- prefers `~/bin/seiton` if `~/bin` is already on `PATH`\n- otherwise prefers `~/.local/bin/seiton` if that directory is already on `PATH`\n- otherwise installs to `~/.local/bin/seiton`\n\nThe Settings panel also shows:\n\n- whether the command is installed\n- whether the target directory is on `PATH`\n- a shell snippet to add that directory to `PATH` if needed\n\nIf you prefer to inspect the built artifact directly, the command source is:\n\n```text\ndist-electron/cli.js\n```\n\n## Agent integration\n\nSeiton supports Codex and Claude status updates through tmux pane options.\n\nThe intended flow is:\n\n```text\nAgent hook -\u003e seiton hook \u003cagent\u003e \u003cevent\u003e -\u003e tmux pane options -\u003e Seiton UI polling\n```\n\n### Supported Codex events\n\n- `SessionStart`\n- `UserPromptSubmit`\n- `Stop`\n\nThese map to:\n\n- `session-start`\n- `user-prompt-submit`\n- `stop`\n\n### Supported Claude events\n\n- `SessionStart`\n- `UserPromptSubmit`\n- `Notification`\n- `Stop`\n- `StopFailure`\n- `PostToolUse`\n- `SessionEnd`\n\n### tmux pane options used by Seiton\n\nSeiton writes and reads these pane options:\n\n- `@seiton_agent`\n- `@seiton_status`\n- `@seiton_prompt`\n- `@seiton_cwd`\n- `@seiton_started_at`\n- `@seiton_attention`\n- `@seiton_wait_reason`\n\nThe current pane status values are:\n\n- `idle`\n- `running`\n- `waiting`\n- `error`\n\n### Prepare the hook command\n\nRun:\n\n```bash\nnpm run build\n```\n\nThen install the command from the Seiton Settings panel, or reference `dist-electron/cli.js` directly.\n\n### Enable Codex hooks\n\nCodex hooks need to be enabled in `~/.codex/config.toml`:\n\n```toml\n[features]\ncodex_hooks = true\n```\n\n### Configure `~/.codex/hooks.json`\n\nRecommended: install the `seiton` command from the Settings panel first, then use `seiton hook ...` directly.\n\nIf you do not want to install the command in `PATH`, you can still call `dist-electron/cli.js` with an absolute path.\n\n### Example with installed `seiton` command\n\n```json\n{\n  \"hooks\": {\n    \"SessionStart\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook codex session-start\"\n          }\n        ]\n      }\n    ],\n    \"UserPromptSubmit\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook codex user-prompt-submit\"\n          }\n        ]\n      }\n    ],\n    \"Stop\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook codex stop\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\n### Example with absolute path\n\nUse absolute paths. Replace `/ABS/PATH/TO/SEITON` with your checkout path.\n\n```json\n{\n  \"hooks\": {\n    \"SessionStart\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"cd /ABS/PATH/TO/SEITON \u0026\u0026 ./dist-electron/cli.js hook codex session-start\"\n          }\n        ]\n      }\n    ],\n    \"UserPromptSubmit\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"cd /ABS/PATH/TO/SEITON \u0026\u0026 ./dist-electron/cli.js hook codex user-prompt-submit\"\n          }\n        ]\n      }\n    ],\n    \"Stop\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"cd /ABS/PATH/TO/SEITON \u0026\u0026 ./dist-electron/cli.js hook codex stop\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nThe hook payload is read from `stdin`, and `TMUX_PANE` is used to know which pane to update.\n\n### Notes about current Codex hook behavior\n\nAs of current Codex CLI behavior, the practical setup is:\n\n- put hooks in `~/.codex/hooks.json`\n- enable `codex_hooks = true`\n\nThis matches the current runtime behavior discussed in `openai/codex` issues:\n\n- plugin-local `hooks.json` is not reliably executed yet: https://github.com/openai/codex/issues/16430\n- commonly available hook events are `SessionStart`, `UserPromptSubmit`, and `Stop`: https://github.com/openai/codex/issues/15490\n\nIf Codex hook behavior changes upstream, update the config example accordingly.\n\n### Claude hook commands\n\nClaude hooks call the same CLI entrypoint with `claude` as the agent name:\n\n```text\nseiton hook claude session-start\nseiton hook claude user-prompt-submit\nseiton hook claude notification\nseiton hook claude stop\nseiton hook claude stop-failure\nseiton hook claude post-tool-use\nseiton hook claude session-end\n```\n\n### Configure `~/.claude/settings.json`\n\nClaude Code reads hooks from `~/.claude/settings.json` (or a project-local `.claude/settings.json`). Add a `hooks` block that calls the `seiton` command for each event Seiton tracks:\n\n```json\n{\n  \"hooks\": {\n    \"SessionStart\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude session-start\"\n          }\n        ]\n      }\n    ],\n    \"UserPromptSubmit\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude user-prompt-submit\"\n          }\n        ]\n      }\n    ],\n    \"Notification\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude notification\"\n          }\n        ]\n      }\n    ],\n    \"Stop\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude stop\"\n          }\n        ]\n      }\n    ],\n    \"StopFailure\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude stop-failure\"\n          }\n        ]\n      }\n    ],\n    \"PostToolUse\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude post-tool-use\"\n          }\n        ]\n      }\n    ],\n    \"SessionEnd\": [\n      {\n        \"hooks\": [\n          {\n            \"type\": \"command\",\n            \"command\": \"seiton hook claude session-end\"\n          }\n        ]\n      }\n    ]\n  }\n}\n```\n\nIf you have not installed the `seiton` command on `PATH`, replace `seiton` with `cd /ABS/PATH/TO/SEITON \u0026\u0026 ./dist-electron/cli.js` in the same way as the Codex absolute-path example above.\n\n### Manual notifications\n\nUse `seiton notify` inside a tmux pane when you need to raise a waiting state manually:\n\n```bash\nseiton notify \"implementation finished\"\n```\n\n## Operational notes\n\n- If `but status -fv` reports `Setup required: No GitButler project found`, Seiton runs `but setup` and retries automatically.\n- If a Kitty tab is missing during focus, Seiton creates one.\n- If a tmux session is missing during focus, Seiton creates one.\n- If a target pane lives in another tmux window, Seiton switches to that window before selecting the pane.\n- Orphan cleanup removes both the tmux session and the matching Kitty tab.\n\n## Limitations\n\n- The app is currently optimized for `kitty + tmux + GitButler`.\n- Agent activity uses tmux pane options first, then falls back to pane inspection for Codex panes when needed.\n- Notification history is not persisted yet.\n- Browser-only Vite mode is not a supported operational mode.\n\n## Development notes\n\nImportant files:\n\n- [electron/main.ts](./electron/main.ts)\n- [electron/preload.ts](./electron/preload.ts)\n- [src/core/commands.ts](./src/core/commands.ts)\n- [src/core/model.ts](./src/core/model.ts)\n- [src/renderer/App.tsx](./src/renderer/App.tsx)\n\nSpecification draft:\n\n- [specs/spec.md](./specs/spec.md)\n# force trigger\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkdnk%2Fseiton","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkdnk%2Fseiton","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkdnk%2Fseiton/lists"}