Commit Graph
2300 Commits
Author SHA1 Message Date
Marko Vejnovic 283881ed4e fix(vendor): find the repository root from the script's location
`git rev-parse --show-toplevel` names the outermost repository, so with atuin
checked out as a subdirectory of another one, `list` and `update` looked for
vendor/.repositories.json in the wrong place.
2026-10-01 22:07:53 -07:00
Marko Vejnovic ee9ebe889e ci: tell hub when main moves
hub keeps atuin's history in its monorepo and syncs it both ways. This
trigger starts that sync on every push to main; the build it starts takes no
input from this one.
2026-10-01 22:07:53 -07:00
Ellie Huxtable e8af845c8c fix(ai-session): count content-derived calls once per session lineage (#4314) 2026-10-01 21:27:44 -07:00
Ellie Huxtable 97fab728a4 feat(ai): add atuin ai resume, a picker over agent sessions (#4311) 2026-10-01 20:52:39 -07:00
dependabot[bot] 1781be0fcb refactor(deps): bump urllib3 from 2.7.0 to 2.8.0 in /docs in the uv group across 1 directory (#4313) 2026-10-01 19:38:41 -07:00
Marko Vejnovic 2e3a4918f7 feat(api-client): add the atuin.api.v1 protos (#4312) 2026-10-01 19:32:12 -07:00
Ellie Huxtable 2e0e2d2472 feat(ai-session): faster sidecar rebuilds, session grouping, and one search API (#4302)
A few thing here in prep for session resume working

1. Incremental builds for ai sessions too. Similar to how we build
history records incrementally. Tracks a watermark, so that on daemon
boot we don't end up having to rebuild the entire harness db again
2. Groups sessions. Previously subagents etc all showed up as brand new
sessions, which was pretty spammy. Fix that up so that subagents are
grouped under the primary session
3. Reduces search params complexity
2026-10-01 11:37:11 -07:00
taylor.fish 2221b09fac refactor: switch from directories to dirs (#4306)
Switch from [`directories`](https://docs.rs/directories) to
[`dirs`](https://docs.rs/dirs). The two crates are both based on
[`dirs_sys`](https://docs.rs/dirs_sys) and return the same results.[^1]

Benefits:

* Faster. `directories` queries *every* potential directory even if you
only need one. For example,
[`dirs::home_dir()`](https://docs.rs/dirs/7/dirs/fn.home_dir.html) is
9.5x faster than [`directories::BaseDirs::new().map(|d|
d.home_dir())`](https://docs.rs/directories/latest/directories/struct.BaseDirs.html#method.home_dir).
* Simpler. Given that we weren't using higher-level features of
`directories` like `ProjectDirs`, the API of `dirs` is simpler.
* Fewer dependencies. We were already transitively pulling in `dirs`;
switching away from `directories` deletes a dependency from our lockfile
without adding any.

[^1]: `dirs` v6 has a [bug](https://codeberg.org/dirs/dirs-rs#7) that
causes `preference_dir` on Windows to diverge from `directories`. We do
not use this function and are thus not impacted. It's not worth
upgrading to v7 just yet, as that would pull in two different versions
of `dirs` in our crate (`shellexpand` depends on v6).
2026-09-30 17:43:18 -07:00
github-actions[bot] 9be0dee744 chore(deps): update flake.lock (#3827) 2026-10-01 00:03:39 +00:00
Ellie Huxtable 90f590b923 fix(ai-session): read an unknown parent kind as None (#4301)
Main rejects a whole synced message if its parent_kind has a value the
build doesn't recognise, so as soon as a newer build adds a kind, older
builds would silently drop those messages; this reads an unknown kind as
"none" and keeps the message.
2026-09-30 16:02:15 -07:00
Ellie Huxtable c8d4d7b5d9 fix: meaning of today in mcp since (#4300)
<!-- 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
- [ ] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the
same thing
2026-09-29 20:06:19 -07:00
Ellie Huxtable 60a444c2d4 fix(daemon): recover ai sessions in the background at boot (#4293) 2026-09-29 19:26:09 -07:00
taylor.fish ef59302c5b feat(pty-proxy): switch from OSC 133 to Atuin-specific sequence (#4291)
Currently we use OSC 133 escape sequences to mark the start and end of
command output for output capture in pty-proxy. However, this has some
problems:

* OSC 133 markers added by other programs or plugins can interfere with
pty-proxy. Atuin's shell integration only emits OSC 133 markers when the
shell is running in the foreground process group of the terminal (e.g.,
not nested inside a multiplexer). However, if another program adds its
own OSC 133 markers, pty-proxy will get confused and start capturing
incorrect data.

* We overload OSC 133 with nonstandard Atuin-specific parameters. We add
a `history_id=<history-id>` parameter to the OSC 133 `D` marker, but
this is nonstandard and could potentially confuse other programs.

* OSC 133 sequences could potentially alter the behavior of other
programs the user is using. Switching to pty-proxy should feel seamless
and should not cause changes beyond the Atuin features it enables.

Therefore, this PR switches away from OSC 133 to a custom Atuin-specific
escape sequence, `OSC 18188735`. This has been chosen to minimize the
chance of conflicts with any existing program or terminal:

* 18188735 is `atuin` interpreted as a base-36 number. It is quite long
and therefore unlikely to be in use.
* 18188735 fits in a signed 32-bit integer, which many terminals use for
OSC numbers. Truncating to 16 or 8 bits produces results that aren't in
use either (35263, 191).
* No prefix of 18188735 of length 3 or greater is in use either, for
terminals that only read a fixed number of digits.

Credit goes to @markovejnovic for the idea to use a custom escape
sequence.

### Testing

I tested the following:

* Update Atuin to this branch and spawn new pty-proxy. Output capture
still works.
* Spawn old pty-proxy, then update Atuin to this branch and spawn
subshell. Output capture still works.
* Tested the above with both the old daemon (v18.23.0) and new daemon
from this branch.
2026-09-29 17:42:04 -07:00
Leon White a88981df79 fix: literal out of range for usize (#4295)
Compilation fails on 32-bit systems with:
```
error: literal out of range for `usize`
   --> crates/atuin-daemon/tests/common/corpus.rs:164:49
    |
164 |         let duration = i64::conv(self.rng.below(5_000_000_000));
    |                                                 ^^^^^^^^^^^^^
    |
    = note: the literal `5_000_000_000` does not fit into the type `usize` whose range is `0..=4294967295`
    = note: `#[deny(overflowing_literals)]` on by default
```
The usize argument to `below` must be less than 4_294_967_295 on 32-bit
systems.

## 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
2026-09-29 16:00:36 -07:00
Ellie Huxtable 7ee02b2ad5 fix(ai): add MCP list cache fields and a since filter for session list (#4294) 2026-09-29 16:00:23 -07:00
Piotr Szlazak 3dcd8ce058 docs: Remove information about dotfiles in support matrix (#4298)
Removing information about dotfiles from support matrix to not confuse
new users.

<!-- 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
2026-09-29 13:07:05 -07:00
taylor.fish c0c9a2ce1a fix: improve "output capture disabled" message (#4296)
If you run `atuin output search` when output capture is disabled, you
get the following error:

```
Error: output capture is disabled. enable [output] in your config to search command output.
```

It is not obvious what it means to `enable [output]`. Now that we have a
command to enable it, it's better to suggest that.
2026-09-29 12:49:31 -07:00
Ellie Huxtable 6f33242ff3 fix: use github release proxy (#4297)
We cannot rely on GitHub to actually be up. I just deployed a github
release proxy, allowlisted on certain repos only, to handle this.

## Checks
- [ ] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the
same thing
2026-09-29 11:49:48 -07:00
Ellie HuxtableandClaude Opus 5.5 c319bf2015 feat(ai): list, read and richer search MCP tools for sessions (#4280)
Adds atuin_ai_session_list and atuin_ai_session_read alongside a
reworked atuin_ai_session_search, so agents can find a past session and
actually read it.


## Checks
- [ ] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the
same thing

---------

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 22:06:28 -07:00
taylor.fish 3c3bcbec95 fix(pty-proxy): preserve login shell status in init script (#4271)
When the pty-proxy init script is run from a login shell, make the child
shell spawned by the PTY proxy also behave as a login shell.

Fixes #4263.
2026-09-28 11:23:40 -07:00
Ellie Huxtable dffaa4a2ea chore: use internal session ids (#4279)
Previously we used the full size session db, which added up to a lot of
disk

## Checks
- [ ] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the
same thing
2026-09-26 23:53:30 -07:00
Ellie Huxtable cc22f75c3a ci(buildkite): build tests once, split test jobs by timing (#4278) 2026-09-26 23:52:03 -07:00
Ellie HuxtableandClaude Opus 5.5 c2ae7351da ci: remove the GitHub Actions workflows Buildkite replaced (#4277)
Remove all workflows that have been replaced with buildkite

We have intentionally moved slow tests (illumos, nix, windows) to be
main only. If fast runners can be found or setup, we can bring them back
again.

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-26 19:39:35 -07:00
Ellie HuxtableandClaude Opus 5.5 2b8631eb2f ci(buildkite): fix the installer hang and address #4274 review (#4275)
Follow-up to #4274, needed before cutting CI over from GitHub Actions.
It fixes the hang on the first `main` build and addresses the review
feedback on #4274 that was never answered before it merged. One commit
per fix.

### Fixes
- **Installer steps hang on `main`** (`ce325a28`). `install.sh` reads
its prompts (import history, `atuin setup`) from `/dev/tty`. GitHub
Actions jobs have no controlling terminal, so it took its
non-interactive path there. The Buildkite agent runs commands in a pty,
so on the first `main` build (#1375) `install` and `install-macos`
waited at "import your existing shell history? [Y/n]" until they timed
out. The installer now runs in a new session with no controlling
terminal, so it detects non-interactive exactly as it did on GitHub
Actions. Reproduced locally under a pty (hangs before the fix, passes
after, for both bash and zsh).
- **P1: the Test Engine token was visible to test code** (`96357dc3`).
The nextest steps had `ATUIN_TEST_ENGINE_TOKEN` in their environment,
and any test, build script or dependency could read it and print it to
this pipeline's public logs. The test steps now only save their JUnit
reports as artifacts, renamed per job by
`.buildkite/hooks/post-command`. A separate `test-engine` step, which
runs no repository code, uploads them with the token.
- **P1: the `.deb` cache could hide a missing package** (`2ff57522`).
The cache is saved once per step, so it can predate a newly added
package, and `dpkg` would then succeed without it. apt_install now
checks every requested package after the fast path, and falls back to
`apt` if one is missing. Tested with stub `dpkg`/`apt-get`. Also
silences apt's "unsandboxed as root" warning.
- **P2: Vale failures could pass** (`18496526`). The step now fails on
Vale's own non-zero exit (config or runtime errors), not only on
reported alerts. Tested: clean docs pass, a planted prose error fails
with exit 1, and a broken config fails with exit 2 where it used to
pass.
- **P2: test Postgres listened on every interface** (`459a50f4`). It now
binds to `127.0.0.1`, and `ATUIN_DB_URI` uses `127.0.0.1`.
- **P2: test coverage for bulk output-index removal** (`8e128df9`). The
chunked statements are split into `Schema::remove_chunked`, and a test
with small chunk sizes checks that removing a mix of indexed and
never-indexed ids drops exactly the indexed ones from both tables. I
confirmed it fails if only the first chunk runs.

**Validated on this PR's build (#1377)**, with the `main`-only installer
steps temporarily enabled on this branch (`fc5186cb`, since reverted in
`ecc93945`):
- `install` and `install-macos` both pass. Each installer took its own
"Non-interactive environment detected" path.
- `test-engine` found the 9 per-job reports (every test shard) and
uploaded all 9 to the atuin suite. No other job has the token.

**Checks:** `atuin-daemon`: 377 tests pass; clippy `-D warnings` and
nightly rustfmt are clean; ShellCheck passes on all scripts and hooks.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-26 19:12:56 -07:00
Ellie HuxtableandClaude Opus 5.5 c7f0318eb3 ci: run CI on Buildkite (#4274)
Move atuin's CI over to Buildkite. I've removed a few jobs from branches
and pushed them onto main, mostly things like the nixos build, illumos
etc - they were really slow, and difficult to optimise.

The goal is to be on buildkit, and have CI take around a minute per
commit. Once we have more tests, we can keep parallelizing

I tested out both the nvme disks and the buildkite cache. The former is
much faster, but is trickier to isolate across branches. I would prefer
that there is 0 chance of a branch messing with a build on main, or with
another branch.

---------

Co-authored-by: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-26 17:45:57 -07:00
Ellie Huxtable d2ddf8c0f9 fix(ai): start the daemon before ai commands if autostart is enabled (#4269)
Unlikely to be hit, as bash will almost certainly run before this does.
But good to have it just in case.

<!-- 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
- [ ] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the
same thing
2026-09-25 18:11:04 -07:00
taylor.fish 9e5e852367 refactor: improve Shell::default_shell; fixes hanging test under Nextest (#4267)
This PR refactors `Shell::default_shell`. The motivating factor is that
it was causing a test to hang and fail when run under Nextest, and
worse, would leave an orphaned process consuming 100% CPU.

Specifically, if `cargo nextest run -E
'test(=doctor_runs_on_fresh_install)'` is run while attached to a
terminal:

* `atuin doctor` calls `Shell::default_shell`.
* `default_shell` runs `sh -ic "getent passwd $LOGNAME"`.
* `-i` makes `sh` (in my case, `dash`) interactive, which turns on job
control, causing `sh` to try to control the terminal.
* Nextest runs every test in its own process group, and that process
group is not the terminal's foreground process group. When a background
process tries to control the terminal, it receives SIGTTIN, which causes
it to stop.
* `sh`, now stopped, waits forever until Nextest times out after 30s.
* After 30s, Nextest kills `atuin doctor` but not `sh`, orphaning `sh`.
* The orphaned `sh` no longer receives SIGTTIN; instead, reads from the
terminal immediately fail.
* In the case of `dash`, it keeps retrying the failing terminal read in
an infinite loop, using 100% CPU.

The following improvements have been made to `Shell::default_shell`:

* It no longer spawns interactive shells, or any shells at all.
* It correctly handles non-UTF-8 output from the query commands it runs.
* It no longer has to query the system name at runtime, relying on the
compile-time configuration instead.
* On Linux, it uses the UID rather than username for lookups, which is
more robust.
* Error messages are more descriptive.
* Allocations have been reduced.

Unused code from `atuin-dotfiles` has been removed as well; it was the
sole user of `Shell::run_interactive`, now also removed by this commit.
2026-09-25 17:31:19 -07:00
Marko Vejnovic f1750cdd6b feat(output): add command_filter to drop output but keep history (#4268) 2026-09-25 16:51:01 -07:00
Marko VejnovicandEllie Huxtable 6557b4e59c feat: capture ai agent sessions into the store (#4212)
Co-authored-by: Ellie Huxtable <[email protected]>
2026-09-25 16:31:00 -07:00
Ellie Huxtable 5b10eb09c6 chore: reduce record store disk usage (#4249)
<!-- 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
- [ ] I am happy for maintainers to push small adjustments to this PR,
to speed up the review cycle
- [ ] I have checked that there are no existing pull requests for the
same thing
2026-09-24 13:50:40 -07:00
taylor.fish 22225ef7fc feat(daemon): store daemon socket path in pidfile (#4253)
Historically we have had several issues related to a mismatch between
what the client thinks the daemon socket path should be and what it
actually is, generally due to environment variable differences (e.g.,
daemon launched without `TMPDIR` set but the client runs with it).

To prevent these kinds of issues going forward, this PR makes the daemon
store the path to its socket in the pidfile. The client, when connecting
to the daemon, uses the socket path in the pidfile if present. This
means that even if you change `daemon.socket_path` in `config.toml`
after launching the daemon, the client will still be able to connect to
it.

### Implementation

Historically, the pidfile had this format:

```
<pid>
<atuin version>
```

This PR changes the format to:

```
<pid>
v1
<PidfileInfo serialized as JSON>
```

where `PidfileInfo` contains the socket path, and version as before.

This change is backward-compatible: the PID is still in the same place,
and we never actually used the version for anything. The version always
starts with a number since it comes from `CARGO_PKG_VERSION`, so `v1`
unambiguously identifies the file as the new format.

To avoid reading the pidfile in a half-written state, we use a new file,
the *pidfile lock* (same path as the pidfile with `.lock` appended) to
guard reads and writes of the pidfile. This mirrors the startup lock
file (`.startup.lock` appended) that we already use.

### New files

* `crates/atuin-daemon/src/pidfile.rs`: New module containing all the
pidfile-related code.
* `crates/atuin-common/src/fs/lock.rs`: New utility module for managing
file locks.
* `crates/atuin-common/src/string/auto_os_string.rs`: Better
serialization of `OsString` with serde.

### Testing

In addition to the unit tests, I performed some smoke testing, including
starting the daemon with a custom `socket_path`, changing the
`socket_path` in `config.toml`, and then making sure the client can
still connect. I also made sure the client can still connect to an older
daemon that doesn't write its path in the pidfile.
2026-09-23 23:10:38 -07:00
Marko Vejnovic 08ffdaea40 fix(ai): saturate file-tracker mtimes and rebuild on new migrations (#4250) 2026-09-23 18:27:41 -07:00
Marko Vejnovic 57657b6324 feat(common): add BlockingPool, a cap on concurrent blocking work (#4242) 2026-09-23 00:50:57 -07:00
Marko Vejnovic 853a746e93 refactor: hold secrets in secrecy types (#4237) 2026-09-22 20:50:51 -07:00
taylor.fish b674d354e6 chore: rename Backoff::Linear to Backoff::Constant (#4238)
`Backoff::Exponential` waits 1ms, 2ms, 4ms, 8ms, etc. – an exponential
curve. This means that `Backoff::Linear` should, in theory, wait 1ms,
2ms, 3ms, and so on – linear growth – but instead it polls with a fixed,
unchanging delay. This makes *constant* a more appropriate name than
linear (a constant function is technically linear, with a slope of 0,
but using the more specific name better communicates what the algorithm
does).
2026-09-22 19:35:58 -07:00
Ellie Huxtable 3d64461e8f feat: enable workspaces by default (#1838) 2026-09-22 18:25:40 -07:00
ZhongYu Li 9bb1c96d91 fix(hook): write absolute executable path to agent configs (#4044) 2026-09-22 18:16:28 -07:00
dependabot[bot] f60557cebe refactor(deps): bump lukemathwalker/cargo-chef from e406ad0 to 9a2089c (#4026)
Bumps lukemathwalker/cargo-chef from `e406ad0` to `9a2089c`.

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-22 18:08:22 -07:00
dependabot[bot] cf1ac52b93 refactor(deps): bump debian from bookworm-20260713-slim to bookworm-20260918-slim (#4025)
Bumps debian from bookworm-20260713-slim to bookworm-20260918-slim.

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-09-22 18:08:14 -07:00
Marko Vejnovic 67f1e2c75d feat(i18n): localize user-facing text with Fluent (#4233) 2026-09-22 18:07:54 -07:00
taylor.fish da78170849 fix: fall back to saving history locally when the daemon can't be started (#4234)
Fixes #3866. When the daemon is enabled but autostart is off, and the
daemon either isn't running or has the incorrect version, history is
silently discarded. This PR falls back to saving history locally in the
client instead.
2026-09-22 17:47:53 -07:00
Brad Frank 9e98e4bedd feat: read login password and key from env or stdin (#3498) 2026-09-22 17:16:19 -07:00
Kid 71e87129ce perf(dotfiles): remove defunct bind feature detection for fish (#2532) 2026-09-22 15:57:41 -07:00
taylor.fish 0626a69833 fix: don't (re)start daemon on history end (#4229)
Fixes #4225. There is no benefit to starting the daemon on history *end*
as the new daemon will have no record of the history entry.
2026-09-22 15:23:53 -07:00
taylor.fish 71a2a7a628 chore: fix Clippy warning about time::Duration (#4231)
`cargo clippy` currently generates this warning:

```
warning: `time::Duration::new` does not refer to a reachable function
 --> /home/taylor/code/atuin/clippy.toml:6:1
  |
6 | / [[disallowed-methods]]
7 | | path = "time::Duration::new"
8 | | reason = "panics on overflow; use atuin_common::time::DurationExt::try_new"
  | |___________________________________________________________________________^
  |
```

`time` 0.3.54 made `Duration` an alias of `SignedDuration` instead of a
struct in its own right, and we're on 0.3.55 now. Clippy can't resolve
the type alias, so this PR updates the path in clippy.toml to point to
`SignedDuration`.
2026-09-22 15:23:44 -07:00
dependabot[bot] ebeacfa9e6 refactor(deps): bump vmactions/omnios-vm from 1.3.4 to 1.3.6 (#4029) 2026-09-22 15:14:22 -07:00
taylor.fish ee4e43c2e9 fix(pty-proxy): fix PTY proxy initialization in fish (#4224)
Fixes #4220.
2026-09-21 22:59:41 -07:00
taylor.fish 0f38cddff3 docs: limit installation methods to those that install the latest version (#4219)
After a team discussion, we've decided to limit the installation methods
mentioned in the docs only to those that will always install the latest
version (potentially lagging by a few days).

This PR removes mentions of installation methods that do not meet this
requirement:

* XBPS (Void Linux): currently v18.16.1.
* Nixpkgs: although unstable is relatively up-to-date (v18.21.0), stable
is currently v18.15.2. Only the Nixpkgs mention is removed; installation
of the repository as a flake is still listed.
2026-09-21 19:32:54 -07:00
taylor.fish 76b8684d89 fix: handling of OSC 133 sequences in prompt (#4221)
Changes:

* Don't strip OSC 133 sequences from the prompt if the PTY proxy isn't
in use. This allows other integrations that rely on OSC 133 to function
as usual.

* Only strip Atuin's OSC 133 sequences from the prompt if, after doing
so, there are no OSC 133 sequences remaining. Otherwise, this likely
indicates that some other program has added its own OSC 133 sequences,
and we don't want to end up half-removing them (e.g., if our end pattern
matches but not the start, we'll strip the "B" marker but not the "A"
one).

Fixes #4149.
2026-09-21 19:32:22 -07:00
f1ee66aea6 fix: timezone awareness during atuin search (#3762)
Co-authored-by: techjoec <[email protected]>
Co-authored-by: Marko Vejnovic <[email protected]>
2026-09-22 01:34:48 +00:00