checkpoint

package
v0.4.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 13, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package checkpoint implements the file + conversation snapshot store behind the TUI's /rewind command and Esc Esc keybinding.

One checkpoint is created per user message: each contains a clone of the conversation history at trigger time and a list of files mutated during the turn. File contents are stored as content-addressed blobs shared across checkpoints in the same session, so a file edited in two consecutive turns stores only its two distinct pre-images.

Layout on disk under ~/.yottacode/checkpoints/:

index.json                          # last-sweep timestamp
<session-id>/
  manifest.json                     # ordered list, cheap to read for the picker
  blobs/<sha256>.blob               # content-addressed pre-image bytes
  <checkpoint-id>/
    meta.json                       # prompt, user_msg_idx, []FileEntry
    messages.json                   # full Session.Messages slice at trigger time

All writes use the .tmp + rename atomic pattern. SnapshotPath is idempotent: repeat calls for the same path within one checkpoint are no-ops, and the blob layer dedupes by sha so two checkpoints that snapshot identical bytes share one blob.

Bash mutations and direct file edits made outside the registered Mutator tools are intentionally NOT tracked — mirrors Claude Code /rewind. The picker footer surfaces this so users aren't surprised.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func DefaultRoot

func DefaultRoot() (string, error)

DefaultRoot returns ~/.yottacode/checkpoints/. Created on demand by New.

Types

type FileEntry

type FileEntry struct {
	Path             string      `json:"path"`
	SHA256           string      `json:"sha256,omitempty"`
	ExistedAtCapture bool        `json:"existed"`
	Mode             os.FileMode `json:"mode"`
}

FileEntry records one path snapshotted into a checkpoint. ExistedAtCapture distinguishes "file existed pre-turn, restore its bytes" from "file did not exist pre-turn, delete it on restore". Mode preserves the permission bits (& 0o777; setuid/setgid stripped on purpose).

type Manifest

type Manifest struct {
	SessionID string          `json:"session_id"`
	Entries   []ManifestEntry `json:"entries"`
}

Manifest is the ordered list of checkpoints for one session.

type ManifestEntry

type ManifestEntry struct {
	CheckpointID  string    `json:"checkpoint_id"`
	Created       time.Time `json:"created"`
	PromptPreview string    `json:"prompt_preview"`
}

ManifestEntry is the cheap-to-load summary the picker reads. One per checkpoint, newest first. PromptPreview is truncated to ~200 chars.

type MessagesSnapshot

type MessagesSnapshot struct {
	SessionID string            `json:"session_id"`
	Captured  time.Time         `json:"captured"`
	Messages  []adapter.Message `json:"messages"`
}

MessagesSnapshot is the format stored at <cp>/messages.json. Carries only the conversation slice — todos are out of scope for v1.

type Meta

type Meta struct {
	CheckpointID string      `json:"checkpoint_id"`
	SessionID    string      `json:"session_id"`
	Created      time.Time   `json:"created"`
	UserPrompt   string      `json:"user_prompt"`
	UserMsgIdx   int         `json:"user_msg_idx"`
	Files        []FileEntry `json:"files"`
}

Meta is the per-checkpoint metadata file. UserMsgIdx is the index into Session.Messages where the triggering user message will land (snapshot is taken before the message is appended).

type Store

type Store struct {
	// contains filtered or unexported fields
}

Store is the filesystem-backed checkpoint engine. One Store per yottacode run; methods are safe under concurrent SnapshotPath calls during a turn (Begin/Restore are not expected to be concurrent with themselves).

func New

func New(root string) (*Store, error)

New opens (or creates) a checkpoint store rooted at the given path. Passing "" defaults to ~/.yottacode/checkpoints/.

func (*Store) Begin

func (s *Store) Begin(sessionID, userPrompt string, userMsgIdx int, history []adapter.Message) (string, error)

Begin creates a new checkpoint for the given session before the user message at userMsgIdx is appended. Stores the conversation pre-image (history) and an initial empty FileEntry list. Returns the new checkpoint id.

The picker uses the manifest entry's PromptPreview to label rows, derived from userPrompt by truncating to 200 chars.

func (*Store) LoadManifest

func (s *Store) LoadManifest(sessionID string) (Manifest, error)

LoadManifest reads the per-session manifest, newest first. Empty manifest (or missing session dir) returns an empty slice without error so the picker can show "no checkpoints yet".

func (*Store) LoadMessages

func (s *Store) LoadMessages(sessionID, cpID string) ([]adapter.Message, error)

LoadMessages returns the conversation snapshot bound to one checkpoint.

func (*Store) LoadMeta

func (s *Store) LoadMeta(sessionID, cpID string) (Meta, error)

LoadMeta returns the meta.json for one checkpoint.

func (*Store) RestoreCode

func (s *Store) RestoreCode(sessionID, cpID string) ([]error, error)

RestoreCode writes each FileEntry's blob back to disk, or deletes the file when ExistedAtCapture is false. Two-phase: write every .tmp first, then rename pass — minimizes the window in which only some files are restored. Returns the list of errors encountered; nil on full success.

func (*Store) Root

func (s *Store) Root() string

Root returns the store's base directory. Useful for tests and the "where do checkpoints live?" footer in the picker.

func (*Store) SnapshotPath

func (s *Store) SnapshotPath(sessionID, cpID, absPath string) error

SnapshotPath captures a pre-image of absPath into the checkpoint, appending a FileEntry to its meta.json. Idempotent on repeat calls for the same path within one checkpoint. Soft on missing file: records ExistedAtCapture=false so restore deletes it.

Returns nil on success. Callers should log but not block on errors — snapshot failures must not abort the user's tool call.

func (*Store) Sweep

func (s *Store) Sweep(ttl time.Duration) (int, error)

Sweep removes manifest entries older than ttl, deletes their checkpoint dirs, and GCs orphaned blobs within each session. A session whose manifest becomes empty has its directory removed entirely. Returns the number of checkpoints removed.

Sweep is opportunistic — callers should run it in a background goroutine on session open. Idempotent and safe to call frequently.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL