commit ba30a806112b939161b29c2c7ce6bc6645a219c2
Author: Blair Nyktas <ncts@debian.org>
Date: Fri Oct 23 20:46:36 2026 +0000
d/patches: refresh
commit 1cc5360345025821653f362f0aa19bbce09f367d
Author: Blair Nyktas <ncts@debian.org>
Date: Fri Oct 23 20:46:17 2026 +0000
d/patches: rm disable-benches, upstream dropped all benchmarks
commit 36b7c3d1888b7c23842b402b4622becef2895214
Author: Blair Nyktas <ncts@debian.org>
Date: Fri Oct 23 20:29:32 2026 +0000
d/copyright: update
commit d4b7be397abb615acda85927c219a9d325124d3b
Merge: 65a2018 854654e
Author: Blair Nyktas <ncts@debian.org>
Date: Fri Oct 23 20:25:14 2026 +0000
debian: improt upstream 18.24.2
commit 65a20182862fa9b8e16be4eef137bbcafba196ca
Author: Blair Nyktas <ncts@debian.org>
Date: Fri Oct 23 20:24:20 2026 +0000
d/patches: fix-session-capture-32bit-overflow
commit 7114d1a79b27616f2dd9e14d62a682d7811fcc90
Author: Brian Cosgrove <cosgroveb@gmail.com>
Date: Fri Oct 9 01:55:10 2026 +0000
Override libyaml detection for yaml-rust2
Assisted-by: Codex:gpt-6-astra
commit 86ae56972ef9b170b297058d7c7fb5c07094d6dd
Author: Brian Cosgrove <cosgroveb@gmail.com>
Date: Mon Sep 21 23:32:25 2026 +0000
Restore Atuin AI support
Assisted-by: Codex:gpt-6-astra
commit 854654ec1ec6d13e0eb2468a6e57b2e2044a2162
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 09:31:13 2026 +0000
chore(release): prepare for release 18.24.2 (atuinsh/atuin#4520)
### Bug Fixes
- *(ai)* Import IntoStaticStr from strum_macros, not strum ([#4480](https://github.com/atuinsh/atuin/issues/4480))
- *(ai)* Improve detection of git repositories ([#4450](https://github.com/atuinsh/atuin/issues/4450))
- *(client)* Resolve relative config paths beside config.toml, not the cwd ([#4479](https://github.com/atuinsh/atuin/issues/4479))
- *(config)* Don't print errors twice ([#4501](https://github.com/atuinsh/atuin/issues/4501))
- *(daemon)* Fetch the server's capabilities until a fetch succeeds
- *(daemon)* Spare a stale pidfile's PID when evicting ([#4512](https://github.com/atuinsh/atuin/issues/4512))
- *(daemon)* Handle daemons not spawned by atuin ([#4516](https://github.com/atuinsh/atuin/issues/4516))
- *(output)* Keep quoted words together in output search ([#4502](https://github.com/atuinsh/atuin/issues/4502))
- *(packfile)* Load only the records inside a manifest's range
- *(pty-proxy)* Standalone init with `atuin pty-proxy init` ([#4449](https://github.com/atuinsh/atuin/issues/4449))
- *(pty-proxy)* Wait for input on a non-blocking inherited stdin ([#4486](https://github.com/atuinsh/atuin/issues/4486))
- *(pty-proxy)* Don't re-exec shells running commands from a string or file ([#4414](https://github.com/atuinsh/atuin/issues/4414))
- *(search)* Don't panic when copying with no results ([#4426](https://github.com/atuinsh/atuin/issues/4426))
- *(server)* Let `ATUIN_*` environment variables override server.toml ([#4456](https://github.com/atuinsh/atuin/issues/4456))
- *(update)* Accept ATUIN_GITHUB_TOKEN ([#4262](https://github.com/atuinsh/atuin/issues/4262))
- Remove duplicated word in the no-history stats message ([#4451](https://github.com/atuinsh/atuin/issues/4451))
- Error printing in `?` handler ([#4448](https://github.com/atuinsh/atuin/issues/4448))
- Normalize relative gitdir paths in worktree resolution ([#4506](https://github.com/atuinsh/atuin/issues/4506))
- Upgrade regressions found in release QA ([#4519](https://github.com/atuinsh/atuin/issues/4519))
### Documentation
- Fix ctrl_n_shortcuts default value ([#4458](https://github.com/atuinsh/atuin/issues/4458))
- List all history list --format variables ([#4460](https://github.com/atuinsh/atuin/issues/4460))
- Fix the --reverse default for history list ([#4472](https://github.com/atuinsh/atuin/issues/4472))
- Mention December default in wrapped --year help ([#4476](https://github.com/atuinsh/atuin/issues/4476))
### Features
- *(common)* AbsPath and AbsPathBuf, Path and PathBuf checked to be absolute ([#4481](https://github.com/atuinsh/atuin/issues/4481))
- *(common)* Find a process's cgroup under cgroup v1 and v2 ([#4513](https://github.com/atuinsh/atuin/issues/4513))
- *(daemon)* Run the daemon as a launchd agent on macOS ([#4517](https://github.com/atuinsh/atuin/issues/4517))
- *(pty-proxy)* Window title follows child process ([#4447](https://github.com/atuinsh/atuin/issues/4447))
- *(secrets)* Keep HashiCorp tokens out of history ([#4445](https://github.com/atuinsh/atuin/issues/4445))
### Miscellaneous Tasks
- Give mono its own nixfmt step and scope atuin's to atuin/
- Say a /merge's landed commit gets CI on main
- Rebuild the apt .deb cache for Ubuntu 24.04 ([#4504](https://github.com/atuinsh/atuin/issues/4504))
- Remove the benchmarks ([#4511](https://github.com/atuinsh/atuin/issues/4511))
### Performance
- *(common)* Compile the vendor regexes once ([#4485](https://github.com/atuinsh/atuin/issues/4485))
- *(common)* Drop the tree watcher's file-id cache ([#4492](https://github.com/atuinsh/atuin/issues/4492))
- *(common)* Release a line reader's buffer at the end of the file ([#4494](https://github.com/atuinsh/atuin/issues/4494))
- *(common)* Keep no tree watcher entry for a rejected file ([#4493](https://github.com/atuinsh/atuin/issues/4493))
- *(daemon)* Warm up only a resumed session's unanswered calls ([#4490](https://github.com/atuinsh/atuin/issues/4490))
- *(packfile)* Compress packs in one shot ([#4484](https://github.com/atuinsh/atuin/issues/4484))
### Refactor
- *(daemon)* Managed daemon service with multiple backends ([#4488](https://github.com/atuinsh/atuin/issues/4488))
- *(daemon)* Move daemon startup into the service module ([#4503](https://github.com/atuinsh/atuin/issues/4503))
- *(daemon)* Keep where the daemon listens behind service::address ([#4514](https://github.com/atuinsh/atuin/issues/4514))
- *(daemon)* Take up the daemon's socket in SocketHolder, not Backend ([#4515](https://github.com/atuinsh/atuin/issues/4515))
- *(deps)* Bump clap_complete_nushell from 4.6.0 to 4.6.2 ([#4473](https://github.com/atuinsh/atuin/issues/4473))
- *(deps)* Bump clap_complete from 4.6.9 to 4.6.11 ([#4396](https://github.com/atuinsh/atuin/issues/4396))
- *(deps)* Bump ratatui from 0.30.0 to 0.30.2 ([#4474](https://github.com/atuinsh/atuin/issues/4474))
- *(deps)* Bump certifi from 2025.11.12 to 2026.10.19 in /docs in the uv group across 1 directory ([#4500](https://github.com/atuinsh/atuin/issues/4500))
- *(pty-proxy)* Run on tokio with the parser on its own runtime ([#4482](https://github.com/atuinsh/atuin/issues/4482))
- *(pty-proxy)* Forward captures to the daemon on the proxy's runtime ([#4487](https://github.com/atuinsh/atuin/issues/4487))
- *(pty-proxy)* Rename the screen's parser to Emulator ([#4510](https://github.com/atuinsh/atuin/issues/4510))
- *(pty-proxy)* Migrate output parsing to vte ([#4518](https://github.com/atuinsh/atuin/issues/4518))
### Testing
- *(daemon)* Run the output index tests under rstest ([#4496](https://github.com/atuinsh/atuin/issues/4496))
commit a26289059013791c4881e350bdbf3a5d3278ecd1
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 08:12:27 2026 +0000
fix: upgrade regressions found in release QA (atuinsh/atuin#4519)
Regressions since v18.24.1 that break things for users on upgrade, found by a QA pass over the next release:
- `fix(pty-proxy)`: bash and zsh exited 127 before their first prompt when `atuin` couldn't run by name and pty-proxy was on (2378529e0).
- `fix(daemon)`: a foreground daemon in a terminal of a Dock-launched app took that app's inherited `XPC_SERVICE_NAME` for its launchd job, so `daemon restart` ran `launchctl kickstart -k` on the app (d923707d0).
- `fix(daemon)`: a daemon forked over SSH while logged out of the desktop blocked the launchd agent at the next GUI login, and every prompt then waited 2-4s on launchd's socket (a2676a7a4). The agent now takes over from a daemon a client forked. A daemon removes its socket file on exit only if it is still the one it bound. A daemon from before run modes is left alone, since clients replace those before installing the agent.
- `fix(server)`: a Service named `atuin` crash-looped the server, because kubelet's `ATUIN_PORT=tcp://...` now overrides server.toml. An empty `ATUIN_*` variable also overrode a valid file value (73a320fcd). With `RUST_LOG` unset the server now logs warnings, not only errors, so the warning shows.
- `fix(config)`: a path setting naming an unset variable, or an empty one, failed every command including `init` and the shell hooks, and `:memory:`/`sqlite:`/`file:` database paths were refused (066b54d30). Unset variables now warn and keep the path as written, as 18.24.1 did; empty paths warn and mean the default. Warnings from loading settings are held until logging is set up, so `init` and `doctor` show them; `--hook` stays quiet.
Workspace nextest passes, except `posix_shells_run_their_command_or_file_instead_of_a_proxy::bash::Login`, which also fails on main when PATH has an empty entry; it passes with a clean PATH. Workspace clippy (with and without `--tests`), nightly fmt and rustdoc are clean.
The fixes were written by Claude agents and tested on macOS. Live launchd and Linux/Windows at runtime are untested.
commit a2676a7a4837bfa064b19b598a7d49a59f80eed6
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 05:55:09 2026 +0000
feat(daemon): run the daemon as a launchd agent on macOS (atuinsh/atuin#4517)
This PR migrates the default macOS daemon path to go through `launchd`, removing the "Process running in background" chip in the Dock on Golden Gate.
## User-facing changes
On macOS, with `daemon.autostart = true`, a client of the user at the console installs and starts the launchd agent `sh.atuin.daemon` instead of forking a daemon. That's only for the default profile (no `ATUIN_HOME` or `ATUIN_CONFIG_DIR`) in the user's own home.
| On macOS, with autostart | Before | Now |
|---|---|---|
| Starting the daemon | The first command after login forks `atuin daemon start --daemonize`, which the Dock shows as a process running in the background. | The first command that needs the daemon installs the agent as `~/Library/LaunchAgents/sh.atuin.daemon.plist`, which starts it right away, and waits for it to answer, as it waits for a forked daemon. From then on, launchd starts it at each login, and whenever a client connects to its socket while it isn't running. macOS says once that it added a background item, and lists it as `atuin` under System Settings > General > Login Items. |
| Upgrading Atuin, or `atuin daemon restart` | The client stops the old daemon and forks its own build. | The client boots the agent out and installs it again, running the client's own executable. The first command of a new build replaces a forked daemon with the agent the same way. |
| The Login Items switch is off | No such switch. | Atuin leaves the agent off and works without the daemon until the switch is back on. |
| `atuin daemon stop` | Stops the daemon, and the next command that needs it forks another. | Boots the agent out, and the next command that needs it installs and starts it again. |
| `atuin config disable daemon` | Stops the daemon. | Also removes the agent, which launchd would otherwise start at the next login. |
| `atuin daemon start` in a terminal | Runs the daemon in the foreground. | Refuses while launchd listens on the agent's socket, as it does until `atuin daemon stop`. `--force` boots the agent out first. |
| Another launchd job, such as `brew services`', runs the daemon | Since atuinsh/atuin#4516, clients leave it to that job. | The daemon also removes Atuin's agent when it starts, which would otherwise fight it for the pidfile at every login. |
| The agent fails to start | - | `daemon.stderr.log` in Atuin's logs directory says why. |
On every platform, a daemon socket that accepts connections but never answers, as a hung daemon's does, or launchd's while its agent fails to boot, no longer hangs clients:
| | Before | Now |
|---|---|---|
| Most commands, such as `atuin daemon status` or search | Wait on it indefinitely (`history start` gives up after 2s). | Give up with "the daemon accepted the connection but didn't answer within ...ms": after `local_timeout` plus 2s (4s by default) while a daemon holds the pidfile, and after 500ms while none does. |
| `atuin daemon stop` and `restart` | Wait on it indefinitely. | Evict it, and `restart` starts a new one. |
| A client with autostart | Waits on it. | Replaces it, if no daemon holds the pidfile. |
Unchanged:
- Linux and Windows, apart from the unanswered socket above.
- macOS with `ATUIN_HOME` or `ATUIN_CONFIG_DIR` set, or without the console, such as over SSH while logged out of the desktop: clients fork the daemon as before. An agent that already runs is controlled through launchd from any of the user's sessions.
- macOS with autostart off: Atuin installs no agent. One installed while autostart was on is still Atuin's to stop and remove.
- The uninstall docs gain a step that removes the agent.
commit 45f0f8b60e790786415ae1b1bb25ee98ddc95b84
Author: bunnysayzz <stfuazzo@gmail.com>
Date: Thu Oct 22 05:26:21 2026 +0000
fix: normalize relative gitdir paths in worktree resolution (atuinsh/atuin#4506)
Fixes atuinsh/atuin#4505.
With workspaces on, a search from a linked worktree returned nothing when the worktree .git file had a relative gitdir, which jj workspaces and git worktree add with worktree.useRelativePaths produce. resolve_git_worktree joined the relative path onto the worktree path and never normalized it, so the workspace filter ended up as cwd LIKE '.../wt/../main%', which matches nothing.
This normalizes the joined gitdir path lexically before walking up to the main repo root, so the filter gets the real main repo path. Added a regression test with a relative gitdir that fails before the fix and passes with it. Ran the in_git_repo tests in atuin-common, all 3 pass. Clippy was not installed on my toolchain, so I could not run it locally.
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing
<!-- atuin-pr-template-necessary-for-ci: v2 -->
Co-authored-by: Marko Vejnovic <marko@atuin.sh>
commit d923707d035b7c17e41903d1658edc780ed5af78
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 04:27:34 2026 +0000
fix(daemon): handle daemons not spawned by atuin (atuinsh/atuin#4516)
Only `daemon.systemd_socket` told clients that something other than Atuin runs the daemon. A daemon that `brew services`, a systemd user unit or another launchd job ran was taken for one a client had forked. A client of another build replaced it, behind the back of a manager that would start its own again.
## What changes for users
Only a daemon that launchd or a systemd user service started, which is what `brew services` runs on both platforms, behaves differently:
| | Before | Now |
|---|---|---|
| A newer client finds the daemon outdated (with `daemon.autostart`), or you run `atuin daemon restart` | The client stops it and forks its own, racing the manager. If the client's daemon wins, the manager keeps starting its own again, and each one exits on the taken pidfile. | The client has launchd (`launchctl kickstart -k`) or systemd (`systemctl --user restart`) restart it, then waits for its own build. The daemon stays the manager's. |
| The same, but the manager runs another atuin than the client, such as `brew services` with a curl-installed atuin earlier on `PATH` | The client replaces it with its own, fighting the manager the same way. | The client refuses: "what runs the daemon starts ..., not this atuin at ...". Search fails with that, and the shell hook saves history locally, as when the daemon is down. The daemon stays outdated until it's restarted through the manager. |
| `atuin daemon stop` | Shuts it down, and launchd starts it straight back. | Refuses, naming the manager's command (`brew services stop atuin`, `systemctl --user stop <unit>`). |
| `atuin daemon start --force` | Kills it and takes its place, and the manager keeps starting its own again. | Logs the refusal without killing it, then fails on the pidfile the daemon still holds. |
commit e065659a40c7cc6741227d80f4de036553bcf9c9
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 04:20:20 2026 +0000
feat(pty-proxy): window title follows child process (atuinsh/atuin#4447)
Under pty-proxy, a terminal that names the program running in it finds the proxy in the foreground of its pty, so every tab says `atuin`. The proxy now titles the terminal after the program in the foreground of its own pty, much as tmux's `automatic-rename` names windows via `OSC 0`.
## Behaviour changes
- Terminals that never showed process names get them now, unless the shell titles the terminal itself.
- After a program sets its own title, the terminal keeps it for the rest of the session. This is standard `OSC 0` behavior.
- Inside tmux the proxy's title becomes the pane title, which the default `status-right` shows in place of the hostname.
commit af714d08b317f35d53e97eeeecd5b18982a9c660
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 03:56:51 2026 +0000
refactor(pty-proxy): migrate output parsing to vte (atuinsh/atuin#4518)
Each read of the child's output went through up to four parsers: the debug highlighter's on the output task, then capture's and the highlighter's again on the emulator thread. All of them were `markers.rs`, a hand-written scanner. `markers.rs` becomes `parser.rs`, which follows the output with `atuin-vte`, Atuin's fork of `vte`. `atuin-vt100` 0.19.2 is built on it too, so the stream parser reads the output as the emulator does.
##Behaviour changes
- `0x9C` no longer ends a marker. A UTF-8 terminal reads it as part of a character, and every shell integration ends its markers with `BEL`. **No user-facing change. Our shell integrations use `BEL` anyways and it's unclear to me why we handled `0x9C`.**
- Controls inside a marker are left out of it, and a marker that `CAN` or `SUB` cuts off, or that any `ESC` ends, counts as sent. **No user-facing change. Our shell integrations do not send any controls inside markers.**
- An unfinished OSC is held whole, rather than its first bytes. `vte` doesn't cap it, so neither the emulator (as on main) nor the parser does; a cap belongs in `atuin-vte`. **This means that memory usage of the `pty-proxy` with malicious applications grows unbounded. `main` had this bug, except that it was only in the `emulator.rs` codepath.**
## Performance
- P50 keystroke latency increased by 30%. This is due to `vte`'s performance problems. It is around 30us on my machine now.
- P99 keystroke latency is unchanged.
- Throughput is unchanged.
- Pty-proxy under adversarial workloads uses about 2% more CPU on average.
commit 80bdb36f9bc949e0d5db34aef82fa1391b525c1e
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 02:35:46 2026 +0000
refactor(daemon): take up the daemon's socket in SocketHolder, not Backend (atuinsh/atuin#4515)
`Backend::listen` ran inside the daemon, but backends belong to the client, which picks one to start and stop the daemon. Off Linux, `ExternalSystemd` built a `Subproc` only to bind its socket. `SocketHolder` now says who holds the socket, the daemon or systemd, and takes it up. Taking systemd's socket moves into `systemd/`, which off Linux has the daemon bind its own.
No behaviour change. `ExternalSystemd` keeps its `cfg(unix)` gate until the next PR in this stack replaces it.
Includes atuinsh/atuin#4513 and atuinsh/atuin#4514, so review only the last commit. Checked the same way as atuinsh/atuin#4514.
## Stack (bottom → top)
1. atuinsh/atuin#4512 fix(daemon): spare a stale pidfile's PID when evicting
2. atuinsh/atuin#4513 feat(common): find a process's cgroup under cgroup v1 and v2
3. atuinsh/atuin#4514 refactor(daemon): keep where the daemon listens behind service::address
4. atuinsh/atuin#4515 refactor(daemon): take up the daemon's socket in SocketHolder, not Backend
5. atuinsh/atuin#4516 feat(daemon): leave a daemon that something else runs to it
6. atuinsh/atuin#4517 feat(daemon): run the daemon as a launchd agent on macOS
Each PR includes the ones below it. Review and merge bottom-up.
commit 65aef2f39657aa3809aecd657f26cae67d127437
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 02:25:32 2026 +0000
refactor(daemon): keep where the daemon listens behind service::address (atuinsh/atuin#4514)
Unix sockets and Windows' TCP port were told apart by cfgs across `service/`. Each platform's `address` module now defines the same names, so the code calling it has no cfgs of its own. The commit lists what moved where.
No behaviour change. Windows clients now pass `--daemonize` as well, which does nothing there. Some public items moved:
- `service::pidfile::SocketPathError` is now `service::address::LocateError`, and `Pidfile::socket_path` is now `DaemonAddress::locate`.
- `client::potential_socket_paths` is gone, and so is the `service::RemoveSocketError` re-export; use `service::address::RemoveSocketError`.
- The pidfile's round-trip proptest now runs on Windows too, over UTF-8 paths only. `AutoOsString`'s own tests round-trip the others.
Includes atuinsh/atuin#4513, so review only the last commit.
- macOS: clippy (default and `--tests`), rustdoc, `atuin-daemon` lib tests and `e2e_daemon` pass.
- Linux (Docker): clippy and the `atuin-common` and `atuin-daemon` lib tests pass.
- Windows (`x86_64-pc-windows-gnu`, cross-compiled): clippy is clean for `atuin-daemon` and `cargo check --tests` passes. Clippy on the `atuin` binary fails with the same 10 errors as main. Not run on Windows itself.
## Stack (bottom → top)
1. atuinsh/atuin#4512 fix(daemon): spare a stale pidfile's PID when evicting
2. atuinsh/atuin#4513 feat(common): find a process's cgroup under cgroup v1 and v2
3. atuinsh/atuin#4514 refactor(daemon): keep where the daemon listens behind service::address
4. atuinsh/atuin#4515 refactor(daemon): take up the daemon's socket in SocketHolder, not Backend
5. atuinsh/atuin#4516 feat(daemon): leave a daemon that something else runs to it
6. atuinsh/atuin#4517 feat(daemon): run the daemon as a launchd agent on macOS
Each PR includes the ones below it. Review and merge bottom-up.
commit a483f50bc439d1cc9a6304c482c65f841a116e0f
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 02:08:23 2026 +0000
feat(common): find a process's cgroup under cgroup v1 and v2 (atuinsh/atuin#4513)
`CgroupV2` finds a process's cgroup in cgroup v2's unified hierarchy, the `0::` line of `/proc/<pid>/cgroup`, and `CgroupV1` the one in the v1 hierarchy a controller or name is bound to, such as systemd's `name=systemd`. The hybrid layout lists both. RHEL 8 and its rebuilds (systemd 239, built with `-Ddefault-hierarchy=legacy`) boot cgroup v1 alone, with no `0::` line: the kernel lists v2's hierarchy only once something mounts it. Nothing calls them yet: a later PR in this stack uses them to tell whether a systemd user unit runs the daemon.
`listed_in`'s cases pass in a standalone crate on macOS. The `reads_the_active_process` tests were not run on this version.
## Stack (bottom → top)
1. atuinsh/atuin#4512 fix(daemon): spare a stale pidfile's PID when evicting
2. atuinsh/atuin#4513 feat(common): find a process's cgroup under cgroup v1 and v2
3. atuinsh/atuin#4514 refactor(daemon): keep where the daemon listens behind service::address
4. atuinsh/atuin#4515 refactor(daemon): take up the daemon's socket in SocketHolder, not Backend
5. atuinsh/atuin#4516 feat(daemon): leave a daemon that something else runs to it
6. atuinsh/atuin#4517 feat(daemon): run the daemon as a launchd agent on macOS
Each PR includes the ones below it. Review and merge bottom-up.
commit ffc6be4e83646f012d4f374907cc1d81dc07df71
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 01:13:09 2026 +0000
fix(daemon): spare a stale pidfile's PID when evicting (atuinsh/atuin#4512)
`atuin daemon start --force` evicts the running daemon before starting its own, and it killed the PID in the pidfile even when no daemon held the pidfile. A daemon that crashed leaves its pidfile behind, and its PID may since have gone to another process. Evicting now signals the PID only while a daemon holds the pidfile.
The regression test dies by SIGTERM without the fix.
## Stack (bottom → top)
1. atuinsh/atuin#4512 fix(daemon): spare a stale pidfile's PID when evicting
2. atuinsh/atuin#4513 feat(common): parse a process's cgroups under cgroup v1 and v2
3. atuinsh/atuin#4514 refactor(daemon): keep where the daemon listens behind service::address
4. atuinsh/atuin#4515 refactor(daemon): take up the daemon's socket in SocketHolder, not Backend
5. atuinsh/atuin#4516 feat(daemon): leave a daemon that something else runs to it
6. atuinsh/atuin#4517 feat(daemon): run the daemon as a launchd agent on macOS
Each PR includes the ones below it. Review and merge bottom-up.
commit 93bbf9c95e68a821b805737d54ed0029496ca498
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 00:36:19 2026 +0000
chore: remove the benchmarks (atuinsh/atuin#4511)
Nothing has run the benchmarks since the CodSpeed workflow was removed in atuinsh/atuin#3812. Buildkite lints and builds only the libraries, binaries and tests, so the benches compiled only when someone ran them by hand.
commit f86a54c2bc43859ab2c2191f64aaa1f2cfb9797e
Author: Marko Vejnovic <marko@atuin.sh>
Date: Thu Oct 22 00:27:33 2026 +0000
refactor(pty-proxy): rename the screen's parser to Emulator (atuinsh/atuin#4510)
`screen.rs`'s `Parser` is the emulator that snapshots the screen, and shares its name with `markers::Parser` (and with the stream parser atuinsh/atuin#4447 adds). It is now `Emulator`, with `EmulatorOptions`, `spawn_emulator` and an `atuin-pty-emulator` thread. No behaviour change.
Tested locally on macOS: clippy, `cargo nextest run -p atuin-pty-proxy`, and the pty-proxy e2e suites. Bash's login case in `e2e_pty_proxy_init` fails, the same way on main.
Drafted with Claude Code.
commit 92a8b9ae1d0bf5fff3e7a2378175b7774001fc0a
Author: Marko Vejnovic <marko@atuin.sh>
Date: Wed Oct 21 01:59:06 2026 +0000
perf(daemon): warm up only a resumed session's unanswered calls (atuinsh/atuin#4490)
Warm-up judged every stored tool call of a resumed session across blocking threads, each keeping its own regex caches; it now judges only the calls left unanswered, 789 of 162k on the replica. Live heap 110 -> 88 MB, measured alone on 18.24.1. Split out of atuinsh/atuin#4483.
commit 131bf9cc1d8f747077da23e27aa59bf347495b96
Author: Marko Vejnovic <marko@atuin.sh>
Date: Wed Oct 21 01:52:58 2026 +0000
perf(common): keep no tree watcher entry for a rejected file (atuinsh/atuin#4493)
Keeps no tree watcher entry for a file the filter rejects, ~1.2-2.4 MB under ~/.claude/projects. Such a file is offered to the filter again each time it's seen, so the filter must stay a cheap, pure function of the path, which all three are. Split out of atuinsh/atuin#4483.
commit b97b5c24b7f67c4b15a522ced7181302e85afe7c
Author: Marko Vejnovic <marko@atuin.sh>
Date: Wed Oct 21 01:16:15 2026 +0000
perf(common): release a line reader's buffer at the end of the file (atuinsh/atuin#4494)
A follower at the end of its file kept the whole buffer its last lines were read into: 63 buffers, ~10.5 MB, in a daemon up for 22h. At the end of the file it now keeps only the line read in part. Split out of atuinsh/atuin#4483.
commit c53fb870b424d759bc91837d6d6056c5fcdc3ab6
Author: Marko Vejnovic <marko@atuin.sh>
Date: Wed Oct 21 01:10:58 2026 +0000
fix(output): keep quoted words together in output search (atuinsh/atuin#4502)
We had a bug where doing `atuin output search "foo bar"` resulted in strings that contained `foo` or `bar`, but really we should have found strings that contain the string `foo bar` as a substring.
This PR fixes that.
commit 70f79f0c833d9cddb37e848d4a0cf90f0fe1b3aa
Author: Uzair Aftab <git@uzaaft.me>
Date: Wed Oct 21 01:03:17 2026 +0000
fix(search): don't panic when copying with no results (atuinsh/atuin#4426)
Found this while I was fuzzing atuin with https://github.com/antithesishq/bombadil
To reproduce:
1. Run `atuin search -i`, or press Ctrl+R in a shell with atuins integration
2. Type a query that matches nothing, e.g. zzzzzz, making sure the result list is empty
3. Press Ctrl+Y
```
atuin exits with code 101:
thread 'main' panicked at library/alloc/src/vec/mod.rs:2265:13:
swap_remove index (is 0) should be < len (is 0)
```
## Checks
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing
commit 9ce0ec8bda4a818c44f5f74426528aed4cd22619
Author: Marko Vejnovic <marko@atuin.sh>
Date: Wed Oct 21 00:57:49 2026 +0000
perf(common): drop the tree watcher's file-id cache (atuinsh/atuin#4492)
Drops the FileIdMap the debouncer kept on macOS and Windows (Linux already runs without one): ~4.6 MB over ~/.claude/projects, and a walk of the whole tree at startup and on each rescan. It also fixes a just-created file's old name staying tracked after a rename. Split out of atuinsh/atuin#4483.
commit 1e22ccf407e6e1231d602ad2f873fc26892ced86
Author: Marko Vejnovic <marko@atuin.sh>
Date: Wed Oct 21 00:25:51 2026 +0000
ci: rebuild the apt .deb cache for Ubuntu 24.04 (atuinsh/atuin#4504)
Every Linux job has failed at the toolchain step since the hosted image moved from Ubuntu 22.04 to 24.04: the `apt_debs` v1 entries restore 22.04's `libssl3` .deb, which breaks 24.04's `libssl3t64`, and apt can't install `libssl-dev` past it. Bumping the key makes each step fetch fresh debs once.
commit 1114043e12bec892f2c3a82415fb6a29026c34b7
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 22:48:16 2026 +0000
refactor(daemon): move daemon startup into the service module (atuinsh/atuin#4503)
Moves the daemon's startup into `service/`.
commit ce31938adf86e4ceb017993dd46abc1eeca3d408
Author: taylor.fish <contact@taylor.fish>
Date: Tue Oct 20 22:27:44 2026 +0000
fix(ai): improve detection of git repositories (atuinsh/atuin#4450)
Improve the detection of Git repositories in Atuin AI: previously, repositories were not detected if their paths contained non-UTF-8 bytes.
commit 243447a6faf57ad224fff6ad90035d968d0a94e0
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue Oct 20 21:39:15 2026 +0000
refactor(deps): bump certifi from 2025.11.12 to 2026.10.19 in /docs in the uv group across 1 directory (atuinsh/atuin#4500)
Bumps the uv group with 1 update in the /docs directory: [certifi](https://github.com/certifi/python-certifi).
Updates `certifi` from 2025.11.12 to 2026.10.19
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/certifi/python-certifi/commit/662df63d7906df66f1f07c0751a3dfe9da14d914"><code>662df63</code></a> Restore unaffected emSign roots (<a href="https://redirect.github.com/certifi/python-certifi/issues/439">#439</a>) (<a href="https://redirect.github.com/certifi/python-certifi/issues/440">#440</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/5cb238caeeb6c30ec1a7309ad3e16a5aa7b10ce8"><code>5cb238c</code></a> Remove emsign (<a href="https://redirect.github.com/certifi/python-certifi/issues/437">#437</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/69494a764d0a08f90838d53d4b0fefd3e84045d6"><code>69494a7</code></a> Bump actions/download-artifact from 8.0.1 to 8.0.2 (<a href="https://redirect.github.com/certifi/python-certifi/issues/436">#436</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/029c7b0913d79e2efb73a216fc5c5e13ef958536"><code>029c7b0</code></a> Bump actions/upload-artifact from 7.0.1 to 7.0.2 (<a href="https://redirect.github.com/certifi/python-certifi/issues/435">#435</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/9d0a8f1f3a0d6b2e38d5773db7afe1a37e4527b6"><code>9d0a8f1</code></a> Add support for Python 3.15 (<a href="https://redirect.github.com/certifi/python-certifi/issues/432">#432</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/db472abf0a37067cb4488f036f4c19adf6b6ec3c"><code>db472ab</code></a> Bump pypa/gh-action-pypi-publish from 1.14.1 to 1.14.2 (<a href="https://redirect.github.com/certifi/python-certifi/issues/431">#431</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/f4bc676bc101fe2235846e37044e8c693d6cbaf4"><code>f4bc676</code></a> 2026.07.22 (<a href="https://redirect.github.com/certifi/python-certifi/issues/428">#428</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/4c91f9c5f9b4676d40d2930025ba04d80dd536f6"><code>4c91f9c</code></a> Bump actions/setup-python from 6.3.0 to 7.0.0 (<a href="https://redirect.github.com/certifi/python-certifi/issues/427">#427</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/01a66c5cf32eadb8f03a0504c24cb44f6d581248"><code>01a66c5</code></a> Bump actions/checkout from 7.0.0 to 7.0.1 (<a href="https://redirect.github.com/certifi/python-certifi/issues/426">#426</a>)</li>
<li><a href="https://github.com/certifi/python-certifi/commit/eb355f41cb71f71012ecf1a4d27a57d0ee2b1337"><code>eb355f4</code></a> Bump pypa/gh-action-pypi-publish from 1.14.0 to 1.14.1 (<a href="https://redirect.github.com/certifi/python-certifi/issues/425">#425</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/certifi/python-certifi/compare/2025.11.12...2026.10.19">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions
You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/atuinsh/atuin/network/alerts).
</details>
commit ab6dfc265f1f7ca9a6a23bd071f47bb586606eb3
Author: taylor.fish <contact@taylor.fish>
Date: Tue Oct 20 21:30:23 2026 +0000
fix(config): don't print errors twice (atuinsh/atuin#4501)
atuinsh/atuin#3952 made `atuin config` print errors twice:
```
$ atuin config set search_mode 123
ERROR error=cannot update config: setting 'search_mode' to '123' would make your configuration invalid
enum RequestedSearchMode does not have variant constructor 123 for key `search_mode`
Error: cannot update config: setting 'search_mode' to '123' would make your configuration invalid
enum RequestedSearchMode does not have variant constructor 123 for key `search_mode`
Location: ...
```
This PR fixes that:
```
$ ./target/debug/atuin config set search_mode 123
Error: cannot update config: setting 'search_mode' to '123' would make your configuration invalid
enum RequestedSearchMode does not have variant constructor 123 for key `search_mode`
Location: ...
```
commit 658b5394900806341d6702e585deb021c2b86574
Author: Daniel Shafer <dan@danielshafer.com>
Date: Tue Oct 20 21:08:12 2026 +0000
fix(pty-proxy): don't re-exec shells running commands from a string or file (atuinsh/atuin#4414)
The bash/zsh preamble re-execs any interactive shell attached to a terminal as `atuin pty-proxy`, which drops the command passed to `bash -ic` or `zsh -ic` and leaves the user at a prompt. Skip the re-exec when BASH_EXECUTION_STRING or ZSH_EXECUTION_STRING is set.
Fixes atuinsh/atuin#4412
Edit by @taylordotfish: I added support for detecting `bash -i <file>` and `zsh -i <file>` too. There are some caveats as it isn't possible to check for this with 100% accuracy. In particular, these cases will continue to have incorrect behavior:
* Zsh:
- If the basename of `<file>` is `zsh` or `-zsh`, we will incorrectly spawn a proxy (though this can depend on whether the shell is a login shell).
- If Zsh is spawned with a custom `argv[0]`, we will, in general, not spawn a proxy even though we should. However, before this PR, we would actually try to execute `argv[0]` which would simply kill the shell, so this is an improvement. (Note that if `argv[0]` happens to be a valid executable, we will still incorrectly execute it as before.)
- If Zsh is an older version that doesn't set `ZSH_ARGZERO`, we can't detect when we're reading from a file and will always spawn a proxy.
* Bash:
- If `<file>` is `bash` or `-bash`, we will incorrectly spawn a proxy (though can depend on whether the shell is a login shell).
- If Bash is invoked via a relative path (`./bin/bash`) and the shell has changed CWD before the proxy check is run, we will not spawn a proxy even though we should.
- If Bash is spawned with a custom `argv[0]`, we will, in general, not spawn a proxy even though we should.
- If Bash is started as a login shell but the user's shell in `/etc/passwd` isn't Bash, we will not spawn a proxy even though we should. However, before this PR, we would incorrectly execute that non-Bash program, so this is an improvement. However, if the `/etc/passwd` shell is a different installation of Bash, we will still incorrectly spawn that other Bash as before.
- If Bash is older than version 5.2, we can't detect when we're reading from a file and will always spawn a proxy.
<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord -->
## Checks
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing
Co-authored-by: taylor.fish <contact@taylor.fish>
commit 61b85b713428d3f9fb8ab937e95803ac2dedf20f
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 20:46:51 2026 +0000
refactor(daemon): managed daemon service with multiple backends (atuinsh/atuin#4488)
commit 2535161ee399f06b1350f24e61710cc65a2de4ce
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 02:56:13 2026 +0000
test(daemon): run the output index tests under rstest (atuinsh/atuin#4496)
Puts the output index tests under `#[rstest]`, as the repo asks of every test. Test-only. Split out of atuinsh/atuin#4483.
commit e76ab39799710c28e8e29ce07433793d7d11048a
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 02:32:39 2026 +0000
refactor(pty-proxy): forward captures to the daemon on the proxy's runtime (atuinsh/atuin#4487)
Follow-up to atuinsh/atuin#4482. With output capture on (`[output] enabled = true`), the atuin binary started a thread with a tokio runtime of its own to connect to the daemon and forward each capture. It now runs as a task on the proxy's runtime.
- `PtyProxy::run` takes the capture config as a closure and calls it on the proxy's runtime, so `semantic_command_capture_config` spawns the forwarder there with `tokio::spawn`. The tracker still takes a `CaptureConfig`, so no pty-proxy tests change.
- Redaction, CPU-bound for up to `REDACT_BUDGET` (250 ms in release), runs in `spawn_blocking`, off the I/O thread.
- Behaviour change: a capture whose redaction panics is dropped with the error logged. Before, the panic took the forwarder thread down for the rest of the session.
Dist profile, macOS on Apple Silicon, capture on, each binary with its own home and daemon, 7 rounds in shuffled order, medians:
| | `e9b1f1874` (main) | `fe10e2cce` (this PR) |
|---|---|---|
| threads | 4 | 3 |
| echo round trip p50 / p99 | 16.5 / 37.9 µs | 17.1 / 30.4 µs |
| `cat` of 26 MB, throughput | 45.6 MB/s | 46.8 MB/s |
| `cat` of 26 MB, CPU | 0.94 s | 0.95 s |
| RSS, idle | 16.0 MB | 16.3 MB |
| startup p50 | 12.2 ms | 12.1 ms |
The benchmark produces no captures (no shell integration), so the forwarder only connects; `e2e_capture` covers captures reaching the daemon through the proxy. Capture is off by default, so the thread saved is only for users who opted in.
Verified locally: clippy `-D warnings` (default, `--tests`, and the no-`daemon` `client,pty-proxy` build), fmt, rustdoc, nextest for pty-proxy (201 passed), e2e pty / pty-proxy / capture (173 passed).
AI-written; reviewed through the benchmarks and test runs above.
commit 435b2965ae3f3d0debc8b84bfd97f22f97c75679
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 02:21:59 2026 +0000
fix(pty-proxy): wait for input on a non-blocking inherited stdin (atuinsh/atuin#4486)
Follow-up to atuinsh/atuin#4482. When stdin can't be reopened (owned by another user after `su`, or not a terminal), the proxy read it through `tokio::io::stdin()`, which returns `EAGAIN` as an error. If something else sharing the description left it non-blocking, having nothing to read yet ended the input copy and the shell was handed an EOF: the session ended under the user. Not a regression; the thread-based proxy behaved the same.
- `atuin_common::os::unix::io::ReadRetryingExt::read_retrying`: the read-side twin of `write_all_retrying` (atuinsh/atuin#4217), waiting out `EAGAIN` with `poll`.
- The inherited stdin is read through it on the blocking pool, like the inherited stdout since atuinsh/atuin#4482. The reopened-terminal path is unchanged, apart from `tokio::io::copy` becoming the equivalent loop.
Tests: `read_retrying` waits for input on blocking and non-blocking pipes and returns `0` at the end of input; `inherited_stdin_waits_for_input_on_a_non_blocking_pipe` fails with `EAGAIN` on a plain read. Locally: clippy `-D warnings` (default and `--tests`), fmt, rustdoc, nextest for pty-proxy + common (3671 passed), e2e pty / pty-proxy / capture (173 passed). Not benchmarked: the hot path is unchanged.
AI-written; reviewed through the test runs above.
commit 066b54d3041490f1a2da21134c57b07e7b55d27a
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 02:15:00 2026 +0000
fix(client): resolve relative config paths beside config.toml, not the cwd (atuinsh/atuin#4479)
commit 34d7ba656cf1d6c91e530b8529971cbb0564a16c
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 01:48:55 2026 +0000
perf(common): compile the vendor regexes once (atuinsh/atuin#4485)
Drops the second compiled copy of the vendor regexes, ~2.3 MB the daemon held for its lifetime, with no change in speed or matches. Split out of atuinsh/atuin#4483.
commit 7a11740fd1e1252e9180b2db32fe7499d601140e
Author: Marko Vejnovic <marko@atuin.sh>
Date: Mon Oct 19 18:46:28 2026 -0700
ci: say a /merge's landed commit gets CI on main
commit e9b1f1874af7e25ca656af48e7bf45d6218d6f2b
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 01:24:46 2026 +0000
perf(packfile): compress packs in one shot (atuinsh/atuin#4484)
Cuts a backlog upload's zstd working memory from up to ~650 MB to 160-320 MB, with no change in speed or output. Split out of atuinsh/atuin#4483.
commit 3d841bb9b413015330eeb5befd2ee5047bae156b
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 01:16:51 2026 +0000
refactor(pty-proxy): run on tokio with the parser on its own runtime (atuinsh/atuin#4482)
Moves `atuin pty-proxy` from eight threads to three. Everything but the vt100 parser runs as tasks on one current-thread runtime. The parser keeps a thread, driving a current-thread runtime of its own, so parsing output never queues keystrokes behind it. The third thread is tokio's blocking pool, where the CWD updater looks up the shell's directory and `chdir`s into it: either can hang on a dead NFS or FUSE mount, and must not freeze the terminal when it does.
- `AsyncTty` (new, in `atuin_common::os::unix::tty` beside `TtyId`) polls the pty master and the user's terminal through the reactor. The terminal is reopened by name so `O_NONBLOCK` lands on a fresh open file description, not the one fds 0-2 share with our stderr and whatever else the shell handed them to. A terminal that can't be reopened (owned by another user after `su`) falls back to blocking I/O on tokio's blocking pool; there, stdout keeps going through `WriteAllExt::write_all_retrying`, which waits out `EAGAIN` on a description something else made non-blocking (atuinsh/atuin#4217).
- Output is written to the terminal before it goes to the parser: the handoff wakes the parser's thread, and that syscall sat in front of every echoed keystroke.
- The child is reaped on SIGCHLD rather than a blocking `wait`.
- Kept: when stdin ends, the shell gets `\n` + VEOF. The old code did this implicitly through portable-pty's writer `Drop`; without it `printf ... | atuin pty-proxy` hangs forever. `e2e_pty_proxy_stdin` covers it and times out without the fix.
- Removed: `signal-hook`, and the `stdout_write` bench (it measured the old stdout thread's writer).
Dist profile, macOS on Apple Silicon. Each binary runs under a fresh outer pty with `ATUIN_TERMINAL=1` (no capture, no daemon), 7 rounds in shuffled order, medians:
| | `73a320fcd` (main) | `c191367c3` (this PR) |
|---|---|---|
| threads | 8 | 3 |
| echo round trip p50 / p99 | 17.1 / 26.5 µs | 16.2 / 27.6 µs |
| `cat` of 26 MB, throughput | 64.5 MB/s | 66.3 MB/s |
| `cat` of 26 MB, CPU | 0.62 s | 0.75 s |
| RSS, idle | 12.5 MB | 12.8 MB |
| startup p50 | 10.7 ms | 11.6 ms |
The bulk `cat` costs ~20% more CPU than main (a `kevent` per chunk plus the cross-thread handoff to the parser); one noisy run, where main's own CPU jumped from ~0.6 s to 0.73 s, had them level. Thread count and echo p50 held in every run. RSS doesn't drop: the old threads' stacks were mostly untouched virtual memory.
Alternatives measured and dropped:
- ~~Parser as a task on the same current-thread runtime~~: 1 thread and the best latency and CPU, but bulk throughput 8-16% lower, and rendering a large capture would stall keystrokes.
- ~~Parser as a task on a multi-thread runtime~~: 2 workers 51 MB/s (3 threads), 4 workers 59 MB/s (5 threads), 8 workers 66 MB/s (9 threads). The parser and the output task end up serialized on one worker; matching this PR's throughput takes 9 threads.
Verified locally: clippy `-D warnings` (default and `--tests`), nightly fmt, rustdoc, nextest for pty-proxy + common with all features (3653 passed), e2e pty / pty-proxy / capture suites (173 passed).
Not validated: Linux at runtime (the epoll path, reopening `/dev/pts/N`). Developed and benchmarked on macOS only; leaving Linux to CI. Some e2e runs flag one or two different tests as leaky, none of them proxy tests; not checked against main.
Followups:
- The stdin fallback ends the session when an inherited stdin is non-blocking with nothing to read: the copy errors and the shell gets EOF. Not a regression (the old stdin thread did the same), not fixed here.
- With output capture on, the atuin binary still starts its own thread and runtime to forward captures to the daemon (`semantic_command_capture_config`). Folding it into the proxy runtime needs redaction moved off the I/O thread.
AI-written; reviewed through the benchmarks and test runs above.
commit efd1d5c6b35705298e1fc25c3e529e13955d1b81
Author: Marko Vejnovic <marko@atuin.sh>
Date: Tue Oct 20 01:04:36 2026 +0000
feat(common): AbsPath and AbsPathBuf, Path and PathBuf checked to be absolute (atuinsh/atuin#4481)
Adds `AbsPath` and `AbsPathBuf` utilities which fully describe an "absolute path". More safety more good.
commit 58d6b500d873340702fd303696f1eef10077d9d1
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Tue Oct 20 00:13:42 2026 +0000
refactor(deps): bump ratatui from 0.30.0 to 0.30.2 (atuinsh/atuin#4474)
Bumps [ratatui](https://github.com/ratatui/ratatui) from 0.30.0 to 0.30.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/ratatui/ratatui/releases">ratatui's releases</a>.</em></p>
<blockquote>
<h2>ratatui-v0.30.2</h2>
<p><img src="https://github.com/ratatui/ratatui-website/raw/refs/heads/main/src/assets/a-gift.png" alt="a gift" /></p>
<p>We are excited to announce the new version of <code>ratatui</code> - a Rust library that's all about cooking up TUIs 👨🍳🐀</p>
<p>✨ <strong>Release highlights</strong>: <a href="https://ratatui.rs/highlights/v0302/">https://ratatui.rs/highlights/v0302/</a></p>
<p>⚠️ List of breaking changes can be found <a href="https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md">here</a>.</p>
<h3>Features</h3>
<ul>
<li>
<p><a href="https://github.com/ratatui/ratatui/commit/90639c179ddcbe483ea05f21b1ce3fa09767441a">90639c1</a> <em>(uncategorized)</em> Add Termina backend by <code>@joshka</code> in <a href="https://redirect.github.com/ratatui/ratatui/pull/2561">#2561</a></p>
<blockquote>
<h2>Summary</h2>
<ul>
<li>add the <code>ratatui-termina</code> backend crate using the published <code>termina</code>
crate</li>
<li>expose the backend through the <code>termina</code> feature and Ratatui
prelude/backend re-exports</li>
<li>add a small Termina event-loop example and wire the backend into CI,
xtask, README generation, and docs</li>
</ul>
<p>Refs <a href="https://redirect.github.com/ratatui/ratatui/issues/1784">#1784</a></p>
<h2>Validation</h2>
<ul>
<li><code>cargo +nightly fmt</code></li>
<li><code>cargo check -p ratatui-termina --all-features --all-targets</code></li>
<li><code>cargo check -p ratatui --no-default-features --features termina</code></li>
<li><code>cargo check -p xtask</code></li>
<li><code>cargo check -p release-header</code></li>
<li><code>cargo xtask check-backend termina</code></li>
<li><code>cargo xtask test-backend termina</code></li>
<li><code>cargo xtask rdme --check</code></li>
<li><code>markdownlint-cli2 ARCHITECTURE.md ratatui-termina/README.md .github/ISSUE_TEMPLATE/bug_report.md</code></li>
</ul>
<hr />
</blockquote>
</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>
<p><a href="https://github.com/ratatui/ratatui/commit/fce3c80d53d5cf367e62cadf1d5c819947d23e4c">fce3c80</a> <em>(widgets)</em> Require thread-safe shadow effects by <code>@joshka</code> in <a href="https://redirect.github.com/ratatui/ratatui/pull/2584">#2584</a></p>
<blockquote>
<h2>Summary</h2>
<ul>
<li>require custom shadow effects to preserve the auto traits expected by
Block-backed widgets</li>
<li>document the CellEffect auto-trait contract</li>
<li>add a public widget regression test for the affected ratatui::widgets
re-exports</li>
</ul>
</blockquote>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/ratatui/ratatui/blob/main/CHANGELOG.md">ratatui's changelog</a>.</em></p>
<blockquote>
<h2><a href="https://github.com/ratatui/ratatui/releases/tag/ratatui-v0.30.2">0.30.2</a> - 2026-06-19</h2>
<p><img src="https://github.com/ratatui/ratatui-website/raw/refs/heads/main/src/assets/a-gift.png" alt="a gift" /></p>
<p>We are excited to announce the new version of <code>ratatui</code> - a Rust library that's all about cooking up TUIs 👨🍳🐀</p>
<p>✨ <strong>Release highlights</strong>: <a href="https://ratatui.rs/highlights/v0302/">https://ratatui.rs/highlights/v0302/</a></p>
<p>⚠️ List of breaking changes can be found <a href="https://github.com/ratatui/ratatui/blob/main/BREAKING-CHANGES.md">here</a>.</p>
<h3>Features</h3>
<ul>
<li>
<p><a href="https://github.com/ratatui/ratatui/commit/90639c179ddcbe483ea05f21b1ce3fa09767441a">90639c1</a> <em>(uncategorized)</em> Add Termina backend by <code>@joshka</code> in <a href="https://redirect.github.com/ratatui/ratatui/pull/2561">#2561</a></p>
<blockquote>
<h2>Summary</h2>
<ul>
<li>add the <code>ratatui-termina</code> backend crate using the published <code>termina</code>
crate</li>
<li>expose the backend through the <code>termina</code> feature and Ratatui
prelude/backend re-exports</li>
<li>add a small Termina event-loop example and wire the backend into CI,
xtask, README generation, and docs</li>
</ul>
<p>Refs <a href="https://redirect.github.com/ratatui/ratatui/issues/1784">#1784</a></p>
<h2>Validation</h2>
<ul>
<li><code>cargo +nightly fmt</code></li>
<li><code>cargo check -p ratatui-termina --all-features --all-targets</code></li>
<li><code>cargo check -p ratatui --no-default-features --features termina</code></li>
<li><code>cargo check -p xtask</code></li>
<li><code>cargo check -p release-header</code></li>
<li><code>cargo xtask check-backend termina</code></li>
<li><code>cargo xtask test-backend termina</code></li>
<li><code>cargo xtask rdme --check</code></li>
<li><code>markdownlint-cli2 ARCHITECTURE.md ratatui-termina/README.md .github/ISSUE_TEMPLATE/bug_report.md</code></li>
</ul>
<hr />
</blockquote>
</li>
</ul>
<h3>Bug Fixes</h3>
<ul>
<li>
<p><a href="https://github.com/ratatui/ratatui/commit/fce3c80d53d5cf367e62cadf1d5c819947d23e4c">fce3c80</a> <em>(widgets)</em> Require thread-safe shadow effects by <code>@joshka</code> in <a href="https://redirect.github.com/ratatui/ratatui/pull/2584">#2584</a></p>
<blockquote>
<h2>Summary</h2>
<ul>
<li>require custom shadow effects to preserve the auto traits expected by
Block-backed widgets</li>
<li>document the CellEffect auto-trait contract</li>
<li>add a public widget regression test for the affected ratatui::widgets</li>
</ul>
</blockquote>
</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/ratatui/ratatui/commit/e665c36cb14752a61cd777fbd06dbef8474f2add"><code>e665c36</code></a> chore(ratatui): unleash the rats v0.30.2 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2581">#2581</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/2700b168b57dd88b9e0fb4ea177673c2e95f3090"><code>2700b16</code></a> docs(changelog): update changelog for 0.30.2 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2608">#2608</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/e306ce69df3113d41c00c483e36ba3ecc88f3c79"><code>e306ce6</code></a> fix(buffer): create updates for "uncovered" cells (<a href="https://redirect.github.com/ratatui/ratatui/issues/2587">#2587</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/81e667f354489a809e0db1f95e378efe859dd409"><code>81e667f</code></a> fix(scrollbar): keep a large thumb within the track at the end (<a href="https://redirect.github.com/ratatui/ratatui/issues/2594">#2594</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/c75d7782be5c8157b0c140821090a13fd8cb8eb0"><code>c75d778</code></a> chore(ci): add cargo-udeps dependency check (<a href="https://redirect.github.com/ratatui/ratatui/issues/2599">#2599</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/25314d812972b4cff30f863439021575b7a00217"><code>25314d8</code></a> build(deps): bump release-plz/action from 0.5.129 to 0.5.130 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2600">#2600</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/35340703e8aa2d314870b9022cb75d899cf49b14"><code>3534070</code></a> build(deps): bump taiki-e/install-action from 2.81.8 to 2.81.10 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2601">#2601</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/a798a13b53f865f46c7b7e4e56da8640b354547b"><code>a798a13</code></a> build(deps): bump tombi-toml/setup-tombi from 1.1.2 to 1.1.3 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2602">#2602</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/3ac885038ee6fc2ab043b7421b922f1800159829"><code>3ac8850</code></a> build(deps): bump octocrab from 0.52.0 to 0.53.1 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2603">#2603</a>)</li>
<li><a href="https://github.com/ratatui/ratatui/commit/9c7963341a0479e02bf92091c57fc0ee82ed1f4e"><code>9c79633</code></a> build(deps): bump time from 0.3.47 to 0.3.49 (<a href="https://redirect.github.com/ratatui/ratatui/issues/2604">#2604</a>)</li>
<li>Additional commits viewable in <a href="https://github.com/ratatui/ratatui/compare/ratatui-v0.30.0...ratatui-v0.30.2">compare view</a></li>
</ul>
</details>
<br />
commit 14fbb9587d2243984dcbaa160c2099ff020a7574
Author: Max 👨🏽💻 Coplan <mchcopl@gmail.com>
Date: Tue Oct 20 00:08:22 2026 +0000
fix(update): accept ATUIN_GITHUB_TOKEN (atuinsh/atuin#4262)
## Summary
- Pass `ATUIN_GITHUB_TOKEN` to axoupdater for `atuin update` and `atuin update --check`.
- Document using `gh auth token` when a shared cloud IP has exhausted GitHub's unauthenticated API limit.
The installer already accepts `ATUIN_GITHUB_TOKEN`, so this gives both update paths the same token setting. Without the variable, the updater keeps its current behavior.
Closes atuinsh/atuin#4261
## Verification
- `cargo +nightly fmt --all -- --check`
- `cargo +1.98.0 check --package atuin --features self-update`
Co-Authored-By: OpenAI Codex <noreply@openai.com>
Co-authored-by: Marko Vejnovic <marko@atuin.sh>
commit d9795ad24fe43c0d1c0df5d57115d21957ac1220
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon Oct 19 23:06:45 2026 +0000
refactor(deps): bump clap_complete from 4.6.9 to 4.6.11 (atuinsh/atuin#4396)
Bumps [clap_complete](https://github.com/clap-rs/clap) from 4.6.9 to 4.6.11.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/clap-rs/clap/commit/2cb76fdf385396f86f37af49784504da560b6e47"><code>2cb76fd</code></a> chore: Release</li>
<li><a href="https://github.com/clap-rs/clap/commit/0b00b8d330d55fb8731768578ea7247981779254"><code>0b00b8d</code></a> docs: Update changelog</li>
<li><a href="https://github.com/clap-rs/clap/commit/34430008f695f43d37364ce47cce5156febb1c52"><code>3443000</code></a> Merge pull request <a href="https://redirect.github.com/clap-rs/clap/issues/6526">#6526</a> from bonnefoa/fix-completion-escape</li>
<li><a href="https://github.com/clap-rs/clap/commit/a1b6be720e59248d8b783c1dfce76a355e170dd7"><code>a1b6be7</code></a> fix(clap_complete): Fix value escape in zsh completion</li>
<li><a href="https://github.com/clap-rs/clap/commit/face9e81df3fdbd432d3d97fb69162b33c06036b"><code>face9e8</code></a> test(complete): Add completion test without arg's help</li>
<li><a href="https://github.com/clap-rs/clap/commit/88053ab75fd8576796d9226bcc710d057d42109b"><code>88053ab</code></a> test(complete): Re-enable complete tests</li>
<li><a href="https://github.com/clap-rs/clap/commit/e6adcc21a6b4ea285bd646e977884c8d653841b7"><code>e6adcc2</code></a> chore(release): Simplify replacements</li>
<li><a href="https://github.com/clap-rs/clap/commit/13f2db5072d600c11d8d6298e4e9ba53ffc6c1ab"><code>13f2db5</code></a> chore: Release</li>
<li><a href="https://github.com/clap-rs/clap/commit/3304fead40c107f92f63daccf25af7b4f34ba709"><code>3304fea</code></a> docs: Update changelog</li>
<li><a href="https://github.com/clap-rs/clap/commit/7b2ad34cfd8742757ebd9f5b3e9211cbb66f7c2f"><code>7b2ad34</code></a> Merge pull request <a href="https://redirect.github.com/clap-rs/clap/issues/6521">#6521</a> from r-near/feat/derive-deferred-initialization</li>
<li>Additional commits viewable in <a href="https://github.com/clap-rs/clap/compare/clap_complete-v4.6.9...clap_complete-v4.6.11">compare view</a></li>
</ul>
</details>
<br />
commit e09f771b9507d25310ce4135e8913f8a2d3cf422
Author: Marko Vejnovic <marko@atuin.sh>
Date: Mon Oct 19 22:48:56 2026 +0000
fix(ai): import IntoStaticStr from strum_macros, not strum (atuinsh/atuin#4480)
Unblocks atuinsh/atuin#4474.
`strum::IntoStaticStr` only exists when strum 0.27's `derive` feature is on, and the workspace never turns it on. It resolved because ratatui-widgets 0.3.0 depends on strum 0.27 with `derive`, and Cargo's feature unification switched it on for us too. ratatui 0.30.2 moves ratatui-widgets to strum 0.28, so `atuin-ai` stops compiling. Every other strum derive in the workspace already comes from `strum_macros`.
Verified with `cargo clippy --workspace --all-features --lib --bins --tests -- -D warnings`, clean both on `main`'s lockfile and after `cargo update -p ratatui --precise 0.30.2`.
Not fixed here: the workspace pairs `strum` 0.27 with `strum_macros` 0.28, and the `strum_macros` feature on `strum` builds strum_macros 0.27 without exposing anything from it.
commit 6c9f159b8e39672f60960d255d0ac582c5f6338f
Author: Marko Vejnovic <marko@atuin.sh>
Date: Mon Oct 19 15:48:40 2026 -0700
ci: give mono its own nixfmt step and scope atuin's to atuin/
commit 73a320fcd060710be1d5d484e15d61024cb087b9
Author: huang <13165998033@163.com>
Date: Mon Oct 19 21:26:58 2026 +0000
Fix server environment variables overriding server.toml (atuinsh/atuin#4456)
## Summary
- load server.toml before ATUIN_* environment variables so environment values take precedence
- add a regression test for source precedence
## Validation
- cargo test --locked -p atuin-server settings::tests
- cargo check --locked -p atuin-server
Fixes atuinsh/atuin#4454
Co-authored-by: Marko Vejnovic <marko@atuin.sh>
commit 2378529e0fb279c82c2b607e4b2521c6e0563166
Author: taylor.fish <contact@taylor.fish>
Date: Mon Oct 19 19:59:29 2026 +0000
fix(pty-proxy): standalone init with `atuin pty-proxy init` (atuinsh/atuin#4449)
If a user has this this in their `.bashrc` but does not have pty-proxy enabled in `config.toml`:
```sh
eval "$(atuin init bash)"
eval "$(atuin pty-proxy init bash)"
```
Atuin will not start a PTY proxy. This is a regression caused by atuinsh/atuin#4079.
Users *should* generally enable PTY proxy in the config and remove the redundant separate `atuin pty-proxy init`, but we shouldn't regress the behavior of users who have this older setup.
commit 594c0ab6b6db151d78e18bb724785fc59a6ccf0a
Author: taylor.fish <contact@taylor.fish>
Date: Mon Oct 19 19:51:18 2026 +0000
fix: error printing in `?` handler (atuinsh/atuin#4448)
If the Atuin process launched by the `?` keybinding exits with an error, the error message is not written to the terminal normally, but is instead put into the readline prompt in the user's shell (i.e., if the user then presses enter, their shell will try to execute the error message as a command).
This PR fixes the behavior so error messages are printed normally, using the same approach as the `Ctrl+]` handler.
commit a9e12e07af00eb03ff8e923f8f0a915ce7d11d8e
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date: Mon Oct 19 19:44:35 2026 +0000
refactor(deps): bump clap_complete_nushell from 4.6.0 to 4.6.2 (atuinsh/atuin#4473)
Bumps [clap_complete_nushell](https://github.com/clap-rs/clap) from 4.6.0 to 4.6.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a href="https://github.com/clap-rs/clap/releases">clap_complete_nushell's releases</a>.</em></p>
<blockquote>
<h2>v4.6.2</h2>
<h2>[4.6.2] - 2026-07-15</h2>
<h3>Fixes</h3>
<ul>
<li><em>(help)</em> Say <code>alias</code> when there is only one</li>
</ul>
<h2>v4.6.1</h2>
<h2>[4.6.1] - 2026-04-15</h2>
<h3>Fixes</h3>
<ul>
<li><em>(derive)</em> Ensure rebuilds happen when an read env variable is changed</li>
</ul>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a href="https://github.com/clap-rs/clap/blob/main/CHANGELOG.md">clap_complete_nushell's changelog</a>.</em></p>
<blockquote>
<h2>[4.6.2] - 2026-07-15</h2>
<h3>Fixes</h3>
<ul>
<li><em>(help)</em> Say <code>alias</code> when there is only one</li>
</ul>
<h2>[4.6.1] - 2026-04-15</h2>
<h3>Fixes</h3>
<ul>
<li><em>(derive)</em> Ensure rebuilds happen when an read env variable is changed</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/clap-rs/clap/commit/8e50ec891e30cd2af4f9a62a405a5b7ee31aac4f"><code>8e50ec8</code></a> chore: Release</li>
<li><a href="https://github.com/clap-rs/clap/commit/1f7ca4eb9bafd9e0f1aed3bae388e1f6038866c8"><code>1f7ca4e</code></a> chore: Update transitive clap</li>
<li><a href="https://github.com/clap-rs/clap/commit/3e790f2cbedd68759ca6c4e246ef34560f9cdd48"><code>3e790f2</code></a> docs: Update changelog</li>
<li><a href="https://github.com/clap-rs/clap/commit/0b83f878fc82bc1e6d939067ea298e613216118e"><code>0b83f87</code></a> Merge pull request <a href="https://redirect.github.com/clap-rs/clap/issues/6477">#6477</a> from antoniszymanski/master</li>
<li><a href="https://github.com/clap-rs/clap/commit/dee8b8e4f07c092472d3f9131d34dd6f54ef60ea"><code>dee8b8e</code></a> fix(clap_complete_nushell): Set argument type to <code>directory</code> for `ValueHint::...</li>
<li><a href="https://github.com/clap-rs/clap/commit/4a622b4340d5e1fffff60c0ecefdc6882f738159"><code>4a622b4</code></a> chore: Release</li>
<li><a href="https://github.com/clap-rs/clap/commit/e1f6b90d447ac94e3c78aa76c1c54f3e7fe941db"><code>e1f6b90</code></a> docs: Update changelog</li>
<li><a href="https://github.com/clap-rs/clap/commit/a9660f4cc5eee28343842a99d98b9e459a8cef98"><code>a9660f4</code></a> Merge pull request <a href="https://redirect.github.com/clap-rs/clap/issues/6467">#6467</a> from sylvestre/mangen-override-usage</li>
<li><a href="https://github.com/clap-rs/clap/commit/715b812f3b72ebca1d5ce257e0495e1e76aea56f"><code>715b812</code></a> chore: Release</li>
<li><a href="https://github.com/clap-rs/clap/commit/89e6e9b59c6209c5d9817c7d113ad7ad7f6d6907"><code>89e6e9b</code></a> docs: Update changelog</li>
<li>Additional commits viewable in <a href="https://github.com/clap-rs/clap/compare/clap_complete_nushell-v4.6.0...clap_complete_nushell-v4.6.2">compare view</a></li>
</ul>
</details>
<br />
[](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`.
[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)
---
<details>
<summary>Dependabot commands and options</summary>
<br />
You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)
</details>
commit 02d4f8ff92d69531bb09eb8e748cb87e56dc547a
Author: ump45nose <52391318+ump45nose@users.noreply.github.com>
Date: Mon Oct 19 19:38:41 2026 +0000
docs: mention December default in wrapped --year help (atuinsh/atuin#4476)
@pr_at.md
commit 76dcef40418375b5ddee4a28edb6dd29b0480d06
Author: yuwk <1729065730@qq.com>
Date: Mon Oct 19 19:32:20 2026 +0000
docs: fix the --reverse default for history list (atuinsh/atuin#4472)
`atuin history list --reverse` defaults to on, but the reference page documents it as
`(default: false)`.
The flag is declared with `default_value = "true"` in
`crates/atuin/src/command/client/history.rs:105-110`:
```rust
#[arg(long, short, default_value = "true")]
// accept no value
#[arg(num_args(0..=1), default_missing_value("true"))]
// accept a value
#[arg(action = clap::ArgAction::Set)]
reverse: bool,
```
So omitting `--reverse` still gives `reverse == true`, which selects the reversed
iterator at `history.rs:218`. The surrounding rows of the table are correct — `--session`,
`--human` and `--cmd-only` are plain `#[arg(long)] bool` fields that really do default to
false — so this row is the odd one out.
One-line docs fix; "false" and "true" are the same width, so the table column alignment is
untouched.
## Checks
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing
Note: my own atuinsh/atuin#4460 also edits `docs/docs/reference/list.md`, but only the "Supported
variables" block near the bottom, so the two changes don't overlap.
commit bb99c9d095cd2be4214d32c9f67317fb5d8014fc
Author: yuwk <1729065730@qq.com>
Date: Mon Oct 19 19:25:31 2026 +0000
docs: list all history list --format variables (atuinsh/atuin#4460)
<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord -->
## Summary
`docs/docs/reference/list.md` lists 6 "Supported variables" for `atuin history list --format`,
but `--help` advertises 11 and the implementation accepts all of them. A reader who trusts the
docs page doesn't learn that `{author}`, `{intent}`, `{exit}`, `{session}` and `{uuid}` exist.
## Change
```diff
{command}, {directory}, {duration}, {user}, {host} and {time}
+{command}, {directory}, {duration}, {user}, {host}, {author}, {intent}, {exit},
+{time}, {session}, and {uuid}
```
No code changes.
## Evidence
The list mirrors `atuin --help` for this subcommand, from the i18n message
`crates/atuin/i18n/en-US/atuin.ftl:211`:
> `Available variables: {command}, {directory}, {duration}, {user}, {host}, {author}, {intent}, {exit}, {time}, {session}, and {uuid}`
and each of those keys is handled by the formatter in
`crates/atuin/src/command/client/history.rs:319-343` (`"command"`, `"directory"`, `"exit"`,
`"duration"`, `"time"`, `"host"`, `"author"`, `"intent"`, `"user"`, `"session"`, `"uuid"`);
anything else returns `FormatKeyError::UnknownKey` at `:344`.
I deliberately kept to the 11 names that `--help` advertises rather than also documenting
`"relativetime"`, which is implemented at `history.rs:334` but is not part of this
subcommand's help message — that is a separate question about the CLI text, not the docs page.
## Verification
Docs-only; no `.rs` touched, so `cargo fmt`, clippy and MSRV are unaffected. The Buildkite
`Vale` / `codespell` steps were not run locally (no toolchain in this environment); the text
stays inside the existing fenced `text` block and only wraps onto a second line so the list is
not one long line.
Duplicate check:
* `gh pr list --state open --search "list.md in:file"` → no results.
* `gh pr list --state open --search "history list format in:title"` → no results.
* The open PR that adds `--format json` (atuinsh/atuin#3466) changes `crates/atuin/src/command/client/history.rs`
only and does not touch this page.
* My own open PRs (atuinsh/atuin#4451, atuinsh/atuin#4452, atuinsh/atuin#4458, atuinsh/atuin#4459) touch other files.
## Checks
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing
commit c579406f86e157938c6fff115843cc3af6407691
Author: yuwk <1729065730@qq.com>
Date: Mon Oct 19 19:19:36 2026 +0000
docs: fix ctrl_n_shortcuts default value (atuinsh/atuin#4458)
<!-- Thank you for making a PR! Bug fixes are always welcome, but if you're adding a new feature or changing an existing one, we'd really appreciate if you open an issue, post on the forum, or drop in on Discord -->
## Summary
The `macOS Ctrl-n key shortcuts` section documents `Default: `true``, but the option
defaults to `false`. The section's own prose contradicts it: it tells the reader to
"set the `ctrl_n_shortcuts` option to `true` in your config file" to get the Ctrl
shortcuts, which would be a no-op if they were already the default.
## Change
One word in `docs/docs/configuration/config.md`:
```diff
### macOS Ctrl-n key shortcuts
-Default: `true`
+Default: `false`
```
## Evidence
* `crates/atuin-client/src/settings.rs:1567` — `.set_default("ctrl_n_shortcuts", false)?`
* `crates/atuin-client/config.toml:91` — the shipped template line is
`# ctrl_n_shortcuts = false`
* `docs/docs/configuration/config.md:533` — the body of the same section still reads
"set the `ctrl_n_shortcuts` option to `true`", and the example block at `:535-538`
is commented "Use Ctrl-0 .. Ctrl-9 instead of Alt-0 .. Alt-9 UI shortcuts", i.e. an
opt-in.
Nothing else in the repo assumes a `true` default, so the docs line is the stale part.
## Checks
- [x] I am happy for maintainers to push small adjustments to this PR, to speed up the review cycle
- [x] I have checked that there are no existing pull requests for the same thing
## Verification
Docs-only, single token change; `cargo fmt` / clippy / MSRV are unaffected. I did not
run the Buildkite `Vale`/`codespell` steps locally (no toolchain here), but the edit
only flips `true` to `false` inside an existing inline code span on a line whose
surrounding prose is untouched.
Duplicate check: `gh pr list --state open --search "ctrl_n_shortcuts"` returns no
results. The only open PR touching `docs/docs/configuration/config.md` with nearby
content is atuinsh/atuin#3771, and its hunks are at `@@ -73` and `@@ -798 / -810` (the `[keys]`
section) — verified with `gh pr diff 3771`; it never reaches the macOS Ctrl-n section
at 529-538.
commit 254035839ddf2febbb149c3984820f4ab756a06d
Author: yuwk <1729065730@qq.com>
Date: Mon Oct 19 19:12:58 2026 +0000
fix: remove duplicated word in the no-history stats message (atuinsh/atuin#4451)
The message printed when `atuin stats` finds no history repeats "for" ("check your config for for commands ignored..."). Dropped the extra word. Single-word change inside a string literal; no logic touched, so I didn't run a full build.
commit d6f481a482b3eb980224242113934c99b93260c0
Author: Marko Vejnovic <marko@atuin.sh>
Date: Mon Oct 19 11:40:47 2026 -0700
fix(packfile): load only the records inside a manifest's range
Among the 17 debian patches available in version 18.24.1+ds-1 of the package, we noticed the following issues: