TranscriptScanner

Struct TranscriptScanner 

Source
pub struct TranscriptScanner<'a, S: Storage> { /* private fields */ }
Expand description

Orchestrates transcript file scanning with storage integration.

TranscriptScanner provides a high-level API for scanning Claude Code transcript files and inserting events into storage. It handles:

  • Incremental parsing (only reads new content since last scan)
  • Deduplication by UUID
  • Position tracking for future scans

§Example

use mi6_core::{Storage, TranscriptScanner};
use mi6_storage_sqlite::SqliteStorage;
use std::path::Path;

let storage = SqliteStorage::open(Path::new("mi6.db"))?;
let scanner = TranscriptScanner::new(&storage, "my-machine-id");

let result = scanner.scan_file(Path::new("/path/to/transcript.jsonl"))?;
println!("Inserted {} events", result.inserted);

Implementations§

Source§

impl<'a, S: Storage> TranscriptScanner<'a, S>

Source

pub fn new(storage: &'a S, machine_id: impl Into<String>) -> Self

Create a new scanner with the given storage and machine ID.

The machine ID is used to tag events with their source machine, enabling multi-machine aggregation.

Source

pub fn scan_file(&self, path: &Path) -> Result<ScanResult, ScanError>

Scan a transcript file and insert events into storage.

This method:

  1. Loads the last scanned position for the file
  2. Parses new entries since that position
  3. Inserts new events (checking for duplicates by UUID)
  4. Updates the position for future incremental scans
§Returns

Returns a ScanResult with the count of inserted events and parse errors encountered.

§Errors

Returns a ScanError if:

  • The file cannot be read
  • Storage operations fail
Source

pub fn scan_sessions( &self, session_ids: &[&str], ) -> Result<ScanResult, ScanError>

Scan transcripts for specific sessions by ID.

Looks up each session, checks if it has a transcript_path that exists, and scans it. Sessions without transcript paths or with missing files are silently skipped.

§Arguments
  • session_ids - Slice of session IDs to scan
§Returns

Returns an aggregated ScanResult with the total count of inserted events and parse errors across all scanned files.

§Errors

Returns a ScanError if a storage operation fails or a transcript file cannot be parsed.

Source

pub fn backfill_initial_prompt( &self, session_id: &str, transcript_path: &Path, ) -> Result<bool, ScanError>

Backfill the initial prompt for a session from its transcript file.

This is a fallback for when the UserPromptSubmit hook doesn’t fire, such as when Claude is started with an inline prompt like claude 'initial prompt'.

The method:

  1. Checks if the session exists and has no first_user_message
  2. Reads the transcript file to find the first user prompt
  3. Creates a UserPromptSubmit event with the prompt

This is idempotent - if the session already has a first_user_message, this method does nothing.

§Arguments
  • session_id - The session ID to backfill
  • transcript_path - Path to the transcript file
§Returns

Returns true if a prompt was backfilled, false otherwise.

Auto Trait Implementations§

§

impl<'a, S> Freeze for TranscriptScanner<'a, S>

§

impl<'a, S> RefUnwindSafe for TranscriptScanner<'a, S>
where S: RefUnwindSafe,

§

impl<'a, S> Send for TranscriptScanner<'a, S>
where S: Sync,

§

impl<'a, S> Sync for TranscriptScanner<'a, S>
where S: Sync,

§

impl<'a, S> Unpin for TranscriptScanner<'a, S>

§

impl<'a, S> UnwindSafe for TranscriptScanner<'a, S>
where S: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.