sessions

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: Apache-2.0 Imports: 13 Imported by: 0

Documentation

Overview

Package sessions models a coding agent's Claude Code conversation history as a git repository so it survives VM recreates and follows a project across sandboxes.

The model:

  • One bare "history" repo per project at <historyRoot>/<projectID>.git. Its `main` branch is the canonical, accumulated history.
  • Each sandbox checks out its own branch (vm/<sandbox>) into the per-sandbox state dir that the provider already mounts at the guest's ~/.claude. The mounted dir simply becomes a git working tree.
  • On boot we fold the project's `main` into the sandbox branch, so a fresh sandbox for the same project comes up with prior transcripts and memory in its resume picker. On teardown we merge the sandbox branch back into `main`.

Only conversation transcripts (projects/**, which nests Claude Code's per-project memory/) are tracked — never secrets or host-seeded config. See the .gitignore written by Prepare.

This package is host-side and platform-neutral: it shells out to `git` (matching internal/worktree and internal/config) and is wired into the lifecycle by internal/cli. It is currently used by the vz provider only; firecracker (no virtio-fs live mount) needs a copy-out step before this applies, which is deliberately out of scope here.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func BranchFor

func BranchFor(sandboxName string) string

BranchFor returns the per-sandbox branch name for a sandbox.

func EnsureBare

func EnsureBare(historyRoot, projectID string) (string, error)

EnsureBare creates the bare history repo for a project if it does not yet exist and returns its path. `git init --bare` is idempotent, so this is safe to call on every boot. The repo starts with no refs; `main` is created lazily by the first Publish (a project's very first sandbox has nothing to seed from).

func Prepare

func Prepare(bare, claudeDir, branch string) error

Prepare makes claudeDir a git working tree on the sandbox's branch and folds in the project's accumulated `main` so the sandbox boots with prior history. It is idempotent and runs on every `up`:

  1. `git init` claudeDir if needed (safe on a dir that already holds a previous sandbox's state — `git init` never deletes files).
  2. Write the control files (.gitignore/.gitattributes) and point `origin` at the bare repo.
  3. Check out the sandbox branch, commit whatever transcripts already sit in the tree (the previous session's tail), then merge origin/main in.

The merge — never a checkout — is what brings prior history without ever clobbering files already on disk: new transcript files are added, and the union driver resolves the rare overlapping MEMORY.md.

func Preserve

func Preserve(bare, claudeDir, branch string) error

Preserve commits the live tree and pushes the sandbox's branch to the bare repo. It is lossless and deliberately NEVER touches `main`: a detached or destroyed VM's sessions are kept safe on `vm/<name>`, ready to be published later with Publish. This is the teardown step under the explicit-merge model — destroying a throwaway VM no longer pollutes the canonical history.

It also doubles as in-place migration for a pre-feature sandbox: the existing on-disk transcripts become the branch's first commit. A no-op when the sandbox produced no commits.

func ProjectID

func ProjectID(repoPaths []string) string

ProjectID returns a stable, filesystem-safe identifier for the set of repos a sandbox works on. Sandboxes that share the same repo set share one history repo (and therefore one `main`); per design §6 this keys history to the workspace, not to any single repo.

The id is "<label>-<hash>": a human-readable label (the sole repo's basename, or "ws" for a multi-repo workspace) for debuggability, plus a hash of the absolute, sorted, de-duplicated repo paths for uniqueness.

FROZEN: ids name history repos on disk (~/.clawk/history/<id>.git) and are recorded on sandbox records. Changing the label rule, the hash algorithm, or the normalization orphans every existing transcript — any change needs a migration that re-keys the history dir.

func Publish

func Publish(bare, branch string) error

Publish folds a sandbox's preserved branch into the project's canonical `main` — the explicit "this VM's work belongs in the project history" step behind `clawk sessions merge`. It operates on the bare repo alone, so it works even after the VM is destroyed (the branch was pushed during its life). Idempotent: re-publishing an already-merged branch is a no-op.

func Refresh

func Refresh(bare, claudeDir, branch string) error

Refresh is the per-attach sync for a running sandbox. It pulls the curated `main` into the working tree (so the resume list reflects what's been published) and preserves this VM's branch — but, per the explicit-merge model, it does NOT publish to `main`. This is what keeps a long-lived `clawk here` sandbox (which may stay up for weeks and so never re-runs Prepare) current with sessions published elsewhere.

Safe on a live sandbox: a merge from main only ADDS other VMs' transcript files (sessions are single-owner per id) and never rewrites the session being appended; MEMORY.md union-merges.

Types

type BranchInfo

type BranchInfo struct {
	Branch    string // full ref short name, e.g. "vm/feature-x"
	Sandbox   string // the sandbox name (branch without the vm/ prefix)
	LastSeen  string // committer date of the branch tip
	Published bool   // already merged into main
}

BranchInfo describes one preserved session branch.

func ListBranches

func ListBranches(bare string) ([]BranchInfo, error)

ListBranches returns the preserved per-sandbox branches in the bare repo (the vm/<name> refs), each with its last-activity time and whether it has been published into main. Powers `clawk sessions list`.

Jump to

Keyboard shortcuts

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