From fd188da879d977ca847f10708c39dd4801a204c4 Mon Sep 17 00:00:00 2001
From: Michelle Tilley <michelle@michelletilley.net>
Date: Tue, 14 Apr 2026 16:03:08 -0700
Subject: feat: Allow resuming previous AI sessions (#3407)

This PR introduces session continuation to Atuin AI.

* Conversations with Atuin AI are stored in a local SQLite database
* Upon startup, Atuin AI tries to find a session to resume based on its
directory/workspace and the time since the last event
* If found, Atuin AI will show a note that the session has been resumed,
and an event is added to help the LLM know where the invocation
boundaries are
* If not, Atuin AI will create a new conversation
* The user can create a new conversation with `/new`
* The new setting `ai.session_continue_minutes`, which defaults to `60`,
controls how old the last event in a session can be before it's no
longer considered for automatic resuming.

<img width="1055" height="593" alt="image"
src="https://github.com/user-attachments/assets/3f9ff01a-ef64-44a9-b0e2-3a4252c5746f"
/>

## Architecture

A new `SessionService` trait defines an API contract for a service that
can manage session data. `LocalSessionService` implements this, with
`DaemonSessionService` a possible future extension point.

`SessionManager` owns a `dyn SessionService` and delegates as
appropriate.
---
 .../20260413000000_create_ai_sessions.sql          | 32 ++++++++++++++++++++++
 1 file changed, 32 insertions(+)
 create mode 100644 crates/atuin-ai/migrations/20260413000000_create_ai_sessions.sql

(limited to 'crates/atuin-ai/migrations/20260413000000_create_ai_sessions.sql')

diff --git a/crates/atuin-ai/migrations/20260413000000_create_ai_sessions.sql b/crates/atuin-ai/migrations/20260413000000_create_ai_sessions.sql
new file mode 100644
index 00000000..906a5726
--- /dev/null
+++ b/crates/atuin-ai/migrations/20260413000000_create_ai_sessions.sql
@@ -0,0 +1,32 @@
+CREATE TABLE IF NOT EXISTS sessions (
+    id                  TEXT PRIMARY KEY,
+    head_id             TEXT,
+    server_session_id   TEXT,
+    directory           TEXT,
+    git_root            TEXT,
+    created_at          INTEGER NOT NULL,
+    updated_at          INTEGER NOT NULL,
+    archived_at         INTEGER
+);
+
+CREATE INDEX idx_sessions_directory  ON sessions(directory);
+CREATE INDEX idx_sessions_git_root   ON sessions(git_root);
+CREATE INDEX idx_sessions_updated_at ON sessions(updated_at);
+CREATE INDEX idx_sessions_created_at ON sessions(created_at);
+
+CREATE TABLE IF NOT EXISTS session_events (
+    id              TEXT PRIMARY KEY,
+    session_id      TEXT NOT NULL,
+    parent_id       TEXT,
+    invocation_id   TEXT NOT NULL,
+    event_type      TEXT NOT NULL,
+    event_data      TEXT NOT NULL,
+    created_at      INTEGER NOT NULL,
+
+    FOREIGN KEY (session_id) REFERENCES sessions(id)
+);
+
+CREATE INDEX idx_session_events_session_id    ON session_events(session_id);
+CREATE INDEX idx_session_events_parent_id     ON session_events(parent_id);
+CREATE INDEX idx_session_events_invocation_id ON session_events(invocation_id);
+CREATE INDEX idx_session_events_created_at    ON session_events(created_at);
-- 
cgit v1.3.1

