{"id":51485760,"url":"https://github.com/badbread/ctc","last_synced_at":"2026-07-07T06:04:31.461Z","repository":{"id":361235135,"uuid":"1250751150","full_name":"badbread/ctc","owner":"badbread","description":"Start Claude Code sessions on your home server from your phone... one bash file, no server, drive from the Claude app.","archived":false,"fork":false,"pushed_at":"2026-05-29T17:48:03.000Z","size":893,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-05-29T19:20:21.635Z","etag":null,"topics":["bash","claude-code","cli","remote-control","ssh","tmux","tui"],"latest_commit_sha":null,"homepage":null,"language":"Shell","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/badbread.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-26T23:58:18.000Z","updated_at":"2026-05-29T17:48:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/badbread/ctc","commit_stats":null,"previous_names":["badbread/ctc"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/badbread/ctc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badbread%2Fctc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badbread%2Fctc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badbread%2Fctc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badbread%2Fctc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/badbread","download_url":"https://codeload.github.com/badbread/ctc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/badbread%2Fctc/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35216589,"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":["bash","claude-code","cli","remote-control","ssh","tmux","tui"],"created_at":"2026-07-07T06:04:30.734Z","updated_at":"2026-07-07T06:04:31.449Z","avatar_url":"https://github.com/badbread.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ctc: Claude Terminal Connect\n\n**TL;DR** — _SSH to your Linux box, launch a session with `ctc`, then drive it from the native Claude app._\n\n`ctc` runs `claude --remote-control` in a detached tmux session, one per\nproject, and hands you an arrow-key TUI to manage them. Detached, so it\noutlives the shell that started it; the session keeps running in the Claude\napp after you disconnect. One bash file, no daemon, just the SSH you already\ntrust.\n\n### Demo\n\n![ctc demo](docs/media/demo.gif)\n\nThe session manager: launch a new backend, manage the live ones — attach,\ndetach, flip launch/permission modes. Whatever shows up here also shows up\nin the Claude app.\n\n## Why\n\nDriving my box's `claude` from the app meant four steps, every time:\n\n```bash\nssh mybox\ncd ~/projects/whatever\nclaude\n/remote-control      # inside claude, to push it to the app\n```\n\nAnd the session died with the SSH connection — drop the shell, lose `claude`.\nTyping into a raw SSH terminal on a phone is its own punishment: no\nautocomplete, no spellcheck, no dictation, no screenshots.\n\n`ctc` collapses the launch to picking a project from a menu, and because the\nbackend's detached, the SSH session was only ever the ignition. Close it and\ndrive `claude` from the app — autocomplete, spellcheck, dictation, screenshots,\non whatever device you're holding.\n\n## How (and the clock on it)\n\n[Remote Control](https://code.claude.com/docs/en/remote-control) drives a running\n`claude` from the app, but the process has to stay alive and there's no headless\nmode. So: `claude --remote-control` in a detached tmux session, tmux as the\nkeepalive Claude Code doesn't ship.\n\nThat \"doesn't ship\" is the whole risk. `ctc` exists because of an open gap\n([#30447](https://github.com/anthropics/claude-code/issues/30447)). The day\n`--headless` lands, the tmux trick is dead weight and `ctc` is just a launcher\nUI. Built on that clock on purpose.\n\n## vs. the alternatives\n\n- **`claude remote-control` server mode** (`--spawn worktree`, `--capacity`):\n  one process, many sessions, QR to connect. Great when you're *at* the box.\n  `ctc` is for when you're not: per-project backends spun up and managed over\n  SSH. They compose; point `ctc` at server mode if you want one process.\n- **[Claude Code Channels](https://www.macstories.net/stories/first-look-hands-on-with-claude-codes-new-telegram-and-discord-integrations/)**\n  (official TG/Discord/iMessage, preview since 2026-03): messaging ergonomic, and\n  it has the *same* keepalive problem. Anthropic's docs literally say \"combining\n  with tmux, screen, or a background process is the current workaround.\" `ctc`\n  hosts exactly that session. They stack.\n- **web/Electron UIs** (claudecodeui, Codeman, …): browser file tree + shell,\n  plus a service to run and expose. Opposite bet. Nothing to host.\n\n## Setup\n\nNeeds: an always-on Linux box (server, VPS, Pi, WSL, whatever) with `claude`\n**logged in**, `tmux`, and `bash` 4+. A way to securely SSH into it from wherever\nyou are; `ctc` doesn't care how you get there.\n\n`ctc` doesn't touch auth, it just `exec`s `claude` with whatever login's already\non the box.\n\nSingle file, zero deps:\n\n```bash\ncurl -fsSL https://raw.githubusercontent.com/badbread/ctc/main/bin/ctc \\\n  -o ~/.local/bin/ctc \u0026\u0026 chmod +x ~/.local/bin/ctc\n```\n\nRun `ctc`. First run autodetects your project dir (`~/projects`, `~/code`,\n`~/src`, …) or asks once. Config at `~/.config/ctc/config`\n([example](ctc.config.example)), all of it live-editable in `[o] options`.\n\n\u003cdetails\u003e\u003csummary\u003egit clone / installer instead\u003c/summary\u003e\n\n```bash\ngit clone https://github.com/badbread/ctc \u0026\u0026 cd ctc \u0026\u0026 ./install.sh\n```\n\nCopies to `~/.local/bin`, writes a starter config, checks for `claude`/`tmux`.\n`git pull` to update.\n\u003c/details\u003e\n\n\u003cdetails\u003e\u003csummary\u003eRunning ctc inside a container\u003c/summary\u003e\n\n`ctc` persists its config at `~/.config/ctc/config` and history at\n`~/.local/state/ctc/`. Inside a container, those live on the writable layer\nunless you mount them — every restart wipes the projects dir setting and you\nre-pick it on first run. Mount them (and your projects dir, and `~/.claude*`\nso Claude's login + per-project trust survive too):\n\n```bash\ndocker run --rm -it \\\n  -v \"$HOME/.config/ctc:/root/.config/ctc\" \\\n  -v \"$HOME/.local/state/ctc:/root/.local/state/ctc\" \\\n  -v \"$HOME/.claude:/root/.claude\" \\\n  -v \"$HOME/.claude.json:/root/.claude.json\" \\\n  -v \"$HOME/projects:/root/projects\" \\\n  your-image ctc\n```\n\nOr set `CTC_CONFIG_DIR` / `CTC_STATE_DIR` (and `CLAUDE_CONFIG_DIR`) to paths\nthat already live on a mounted volume.\n\u003c/details\u003e\n\n```bash\nctc                 # session manager\nctc my-api          # fuzzy-jump to the project matching \"my-api\"\nctc ~/some/path     # explicit dir\n```\n\n## Managing sessions\n\nThe menu is a process manager for your backends, one tmux session per project.\nThis is the part I actually live in.\n\n- **Real liveness.** `● live` vs `◌ idle · claude exited`, off the pane's actual\n  `pane_current_command` (`claude`/`node` = live), not a bare `has-session`. A\n  crashed backend reads idle, not falsely healthy.\n- **Attach / detach.** `[a]` drops into the running `claude`; **`Ctrl-b d`**\n  detaches back to the menu, session still live and still on the app. Detach ≠\n  quit. `/exit` ends it.\n- **Kill.** `[k]` on one, or the multi-select screen (`Space` mark, `Enter`\n  confirm) to reap a batch.\n- **Settings in `[o]`**, persisted to config: where ctc looks for projects\n  (projects dir + scan depth), plus the per-launch defaults applied to new\n  sessions — launch mode (`detached`/`attach`), permission mode\n  (`acceptEdits`/`auto`/`bypassPermissions`/`default`/`plan`, or Shift+Tab on\n  the main menu to cycle), model, `--remote-control`, `--continue`. Every\n  toggle maps to a real `claude` flag where one exists.\n\n## One-tap launch\n\n`ctc` is a TUI, so any SSH client works as-is. To make launching a single tap,\nforce a TTY and run it on login. `RemoteCommand` wants the full path if `ctc`\nisn't on the non-interactive `PATH` (`~/.local/bin` usually isn't, `which ctc`):\n\n```\nHost ctc\n    HostName your.box.address\n    User you\n    RequestTTY force\n    RemoteCommand ctc           # full path if needed: /home/you/.local/bin/ctc\n```\n\nPhone clients are where this shines, and they each have quirks:\n\n- **Termux** (Android): `pkg install openssh`, host block in `~/.ssh/config`,\n  `ssh ctc`. One word? `echo 'ctc(){ ssh ctc; }' \u003e\u003e ~/.bashrc \u0026\u0026 source ~/.bashrc`.\n  `command not found` = stale shell, re-`source` or reopen; if Termux ignores\n  `~/.bashrc`, use `~/.profile`. Arrows/Tab/Ctrl on the extra-keys row (Ctrl for\n  `Ctrl-b d`).\n- **Blink** (iOS): best iOS TUI client. Host + startup command `ctc`, or\n  `ssh ctc -t ctc`. Modifiers and Shift+Tab work.\n- **Termius**: host + startup snippet `ctc`. Key row has Ctrl/arrows/Tab.\n\nKeys: `↑↓`/`jk` move, `Enter` select, `q`/`Esc` back, bracketed letter\n(`n o k a b /`) jumps straight to the action.\n\n## AI\n\nMost of the code was written with Claude Code.\n\n## License\n\nMIT, see [LICENSE](LICENSE).\n\n\u003chr /\u003e\n\n*Independent, unofficial. \"Claude\"/\"Claude Code\" are Anthropic trademarks; not\naffiliated or endorsed. It just launches the `claude` you already have.*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadbread%2Fctc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbadbread%2Fctc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbadbread%2Fctc/lists"}