{"id":46132970,"url":"https://github.com/mobydeck/atch","last_synced_at":"2026-03-08T00:01:38.681Z","repository":{"id":341494732,"uuid":"1169675512","full_name":"mobydeck/atch","owner":"mobydeck","description":"atch lets you attach and detach terminal sessions","archived":false,"fork":false,"pushed_at":"2026-03-05T23:54:36.000Z","size":88,"stargazers_count":56,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-07T00:02:46.926Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C","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/mobydeck.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-03-01T03:10:52.000Z","updated_at":"2026-03-06T21:31:07.000Z","dependencies_parsed_at":"2026-03-08T00:00:47.097Z","dependency_job_id":null,"html_url":"https://github.com/mobydeck/atch","commit_stats":null,"previous_names":["mobydeck/atch"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/mobydeck/atch","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobydeck%2Fatch","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobydeck%2Fatch/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobydeck%2Fatch/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobydeck%2Fatch/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mobydeck","download_url":"https://codeload.github.com/mobydeck/atch/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mobydeck%2Fatch/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30238078,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-07T23:52:25.683Z","status":"ssl_error","status_checked_at":"2026-03-07T23:52:25.373Z","response_time":53,"last_error":"SSL_read: 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-03-02T04:14:34.885Z","updated_at":"2026-03-08T00:01:38.663Z","avatar_url":"https://github.com/mobydeck.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# atch\n\n`atch` is a small C utility that lets you attach and detach terminal sessions,\nsimilar to the detach feature of `screen/tmux` — but without the terminal emulation,\nmultiple windows, or other overhead.\n\n**The key property of `atch` is transparency.** It does not interpose a\nterminal emulator between you and your program. The raw byte stream flows\ndirectly from the pty to your terminal, exactly as if you had run the program\nin a plain shell. This means:\n\n- **Mouse works.** Mouse reporting, click events, and drag sequences pass\n  through unmodified. No escape-sequence re-encoding, no `set -g mouse on`,\n  no fighting with terminfo databases.\n- **Scroll works.** Programs that use the alternate screen buffer, or that\n  emit their own scroll sequences, behave identically inside and outside an\n  `atch` session. There is nothing to configure.\n- **Colors and graphics work.** True-color, sixel, kitty graphics, OSC\n  sequences — all pass through untouched.\n- **`$TERM` is unchanged.** `atch` does not set or override your terminal\n  type. The program sees exactly the same `$TERM` your shell uses.\n\nIn contrast, `tmux` and `screen` implement their own terminal emulators.\nThey re-encode the output stream, which frequently breaks mouse support,\nscroll behavior, and newer terminal features unless you find and apply the\nright obscure configuration knob — and then remember it on every new machine.\nWith `atch` there is nothing to remember, because there is nothing in the way.\n\nWhen a program runs inside an `atch` session it is protected from the\ncontrolling terminal. You can detach from it, disconnect, and re-attach later\nfrom the same or a different terminal, and the program keeps running\nundisturbed.\n\n**Session history survives everything.** Every byte written to the terminal\nis appended to a persistent log file on disk. When you re-attach — whether\nthe session is still running, crashed, or you have rebooted the machine — the\nfull output history is replayed to your terminal first, so you can see exactly\nwhat happened and pick up right where you left off. No plugins, no\nconfiguration, no manual `script` wrappers. Other session managers keep\nhistory only in memory: when the process dies or the machine reboots, the\noutput is gone. With `atch` it is on disk until you clear it.\n\n## Features\n\n- Attach and detach from running programs\n- Multiple clients can attach to the same session simultaneously\n- **No terminal emulation** — raw output stream is passed through unchanged\n- Sessions persist across disconnects, crashes, and reboots\n- **Full session history on disk** — every line ever written is saved and replayed on re-attach\n- **History survives process exit** — re-opening a session shows the complete prior output before starting fresh\n- Push stdin directly to a running session\n- List all sessions with liveness status\n- Prevents accidental recursive self-attach\n- Tiny and auditable\n\n## Building\n\n```sh\nmake\n```\n\n## Usage\n\n```\natch [\u003csession\u003e [command...]]   Attach to session or create it (default)\natch \u003ccommand\u003e [options] ...\n```\n\nSessions are identified by name. A bare name (no `/`) is stored as a socket\nunder `~/.cache/atch/`. A name containing `/` is used as-is as a filesystem path.\n\nIf no command is given, `$SHELL` is used.\n\n## Commands\n\n| Command | Description |\n|---------|-------------|\n| `atch [\u003csession\u003e [cmd...]]` | Attach to a session, or create it if it doesn't exist (default behavior). Prints a confirmation when a new session is created. |\n| `attach \u003csession\u003e` | Strict attach — fail if the session does not exist. |\n| `new \u003csession\u003e [cmd...]` | Create a new session and attach to it. Prints a confirmation before attaching. |\n| `start \u003csession\u003e [cmd...]` | Create a new session, detached (atch exits immediately). Prints a confirmation on success. |\n| `run \u003csession\u003e [cmd...]` | Like `start`, but atch stays in the foreground instead of daemonizing. |\n| `push \u003csession\u003e` | Copy stdin verbatim to the session. |\n| `kill [-f] \u003csession\u003e` | Gracefully stop a session (SIGTERM, then SIGKILL after 5 s if needed). With `-f` / `--force`, skip the grace period and send SIGKILL immediately. |\n| `clear \u003csession\u003e` | Truncate the on-disk session log. |\n| `list` | List all sessions. Shows `[attached]` when a client is connected, `[stale]` for leftover sockets with no running master. Prints `(no sessions)` when the list is empty. |\n| `current` | Print the current session name and exit 0 if inside a session; exit 1 silently if not. |\n\nShort aliases: `a` → `attach`, `n` → `new`, `s` → `start`, `p` → `push`,\n`k` → `kill`, `l` / `ls` → `list`.\n\n## Options\n\nOptions can appear before the subcommand, before the session name, or after the session name.\n\n| Flag | Description |\n|------|-------------|\n| `-e \u003cchar\u003e` | Set the detach character. Accepts `^X` notation. Default: `^\\`. |\n| `-E` | Disable the detach character entirely. |\n| `-r \u003cmethod\u003e` | Redraw method on attach: `none`, `ctrl_l`, or `winch` (default). |\n| `-R \u003cmethod\u003e` | Clear method on attach: `none` or `move`. |\n| `-z` | Disable suspend-key (`^Z`) processing (pass it to the program instead). |\n| `-q` | Suppress informational messages. |\n| `-t` | Disable VT100 assumptions. |\n| `-C \u003csize\u003e` | Set the on-disk log cap for the session being created. Accepts a bare number (bytes), or a number with `k`/`K` (KiB) or `m`/`M` (MiB) suffix. `0` disables the log entirely. Default: `1m`. |\n\nUse `--` to separate atch options from command arguments that start with `-`:\n\n```sh\natch new mysession -- grep -r foo /var/log\n```\n\n## Examples\n\n**Start a shell session named `work` and attach to it:**\n```sh\natch work\n```\n\n**Start a specific command in a named session:**\n```sh\natch new build -- make -j4\n```\n\n**Attach to an existing session, creating it if needed:**\n```sh\natch work\n```\n\n**Strict attach — fail if the session is not running:**\n```sh\natch attach work\n```\n\n**Detach** from a running session: press `^\\` (Ctrl-\\\\). The session and its\nprogram keep running.\n\n**Re-attach** later:\n```sh\natch work\n```\n\n**Run a command fully detached (no terminal needed):**\n```sh\natch start daemon myserver\n# atch: session 'daemon' started\n```\n\nUse `-q` to suppress confirmation messages in scripts:\n```sh\natch start -q daemon myserver\n```\n\n**Send keystrokes to a running session:**\n```sh\nprintf 'ls -la\\n' | atch push work\n```\n\n**Use a custom detach character:**\n```sh\natch -e '^A' attach work\n```\n\n**List all sessions:**\n```sh\natch list\n```\n\n**Kill a session:**\n```sh\natch kill work\n```\n\n## Session storage\n\nBy default, session sockets are stored in `~/.cache/atch/`. The directory is\ncreated automatically, including `~/.cache` if it does not yet exist.\n\nWhen `$HOME` is unset or empty, `atch` looks up the home directory from the\nsystem user database (`/etc/passwd`). If that also yields nothing useful (or\npoints to `/`), sockets fall back to `/tmp/.atch-\u003cuid\u003e/`.\n\nTo use a custom path, include a `/` in the session name:\n\n```sh\natch new /tmp/mysession\n```\n\n`atch` sets the `ATCH_SESSION` environment variable inside each session to a\ncolon-separated ancestry chain of socket paths, outermost first. A\nnon-nested session has a single path; nested sessions accumulate:\n\n```\nouter session:   ATCH_SESSION=/home/user/.cache/atch/outer\ninner session:   ATCH_SESSION=/home/user/.cache/atch/outer:/home/user/.cache/atch/inner\n```\n\nThis serves two purposes: self-attach prevention (any ancestor in the chain\nis rejected) and session detection from scripts. Use `atch current` to get\nthe human-readable session name — it prints just the basenames separated by\n` \u003e `:\n\n```sh\n# exit code: 0 inside a session, 1 outside\natch current \u0026\u0026 echo \"inside session: $(atch current)\"\n\n# nested session example:\n# outer \u003e inner\n\n# shell prompt example (bash/zsh PS1)\nPS1='$(atch current 2\u003e/dev/null \u0026\u0026 echo \"[$(atch current)] \")$ '\n```\n\nTo test whether you are inside any `atch` session:\n\n```sh\n[ -n \"$ATCH_SESSION\" ] \u0026\u0026 echo \"inside a session\"\n```\n\n## Session history\n\n`atch` keeps two complementary history stores, both replayed automatically\nwhenever you attach — no configuration required.\n\n### On-disk log (persistent)\n\nEvery byte written to the pty is appended to a log file on disk\n(`~/.cache/atch/\u003csession\u003e.log`). The log persists across everything:\n\n- **Detach / re-attach** — re-attaching to a running session replays the\n  complete history before the live stream begins.\n- **Session exit** — once the program exits, the full output remains on disk.\n  Running `atch mysession` again starts a fresh session but first shows\n  everything from the previous one, so you know exactly what it did.\n- **Machine reboot** — the log file survives a reboot. The next time you\n  open the session you see the complete prior output before the new shell\n  starts.\n- **Crash recovery** — if the session process is killed unexpectedly, the\n  log is intact. Nothing is lost.\n\nThis is fundamentally different from `tmux`, `screen`, and `dtach`: they hold\nhistory only in memory. When the process exits or the machine restarts, the\noutput is gone. With `atch` the raw byte stream is on disk until you\nexplicitly clear it with `atch clear \u003csession\u003e`.\n\nThe log is capped at 1 MB by default; once it exceeds that, only the most\nrecent 1 MB is kept. You can change the cap per session with `-C`:\n\n```sh\natch -C 4m new mysession       # 4 MB cap\natch -C 128k start daemon      # 128 KB cap\natch -C 0 start daemon         # no log at all\n```\n\nWhen the log is disabled with `-C 0`, re-attaching to a **running** session\nstill replays recent output from the in-memory ring buffer. Only cold replay\nof a dead session (after the master has exited) is unavailable.\n\nTo change the compiled-in default, build with:\n\n```sh\nmake CFLAGS=\"-DLOG_MAX_SIZE=$((4*1024*1024))\"\n```\n\n### In-memory ring buffer\n\nWhile the session is running, `atch` maintains a 128 KB ring buffer in the\nmaster process. It is the primary replay source when you re-attach: the ring\nreplays the most recent output instantly so your display is current. When the\non-disk log is also present it covers the full history; when logging is\ndisabled (`-C 0`) the ring is the only replay source available while the\nsession is live.\n\nThe ring is lost when the master exits; the on-disk log covers that case.\n\nTo adjust the ring size, build with:\n\n```sh\nmake CFLAGS=\"-DSCROLLBACK_SIZE=$((256*1024))\"\n```\n\nThe value must be a power of two.\n\n### Clearing history\n\nTo wipe the on-disk log and start clean on the next attach:\n\n```sh\natch clear mysession\n```\n\n## Backward compatibility\n\nThe original flag-based syntax is still supported:\n\n```\natch -a \u003csession\u003e              # same as: atch attach \u003csession\u003e\natch -A \u003csession\u003e [cmd...]     # same as: atch [\u003csession\u003e [cmd...]]\natch -c \u003csession\u003e [cmd...]     # same as: atch new \u003csession\u003e [cmd...]\natch -n \u003csession\u003e [cmd...]     # same as: atch start \u003csession\u003e [cmd...]\natch -N \u003csession\u003e [cmd...]     # same as: atch run \u003csession\u003e [cmd...]\natch -p \u003csession\u003e              # same as: atch push \u003csession\u003e\natch -k \u003csession\u003e              # same as: atch kill \u003csession\u003e\natch -l                        # same as: atch list\natch -i                        # same as: atch current\n```\n\nExisting scripts do not need to be updated.\n\n## License\n\nGPL. Based on dtach by Ned T. Crigler.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobydeck%2Fatch","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmobydeck%2Fatch","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmobydeck%2Fatch/lists"}