# feat(import): discover repo transcripts with one-month lookback

`b3021b4`→[main](/content/gh/entireio/cli/commits/main/index.html)·

computermode·3w ago·2 files·+114 added/-0 removed

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

## Sessions

487abe46ddadView transcript

[?\
Implement Claude History Import FeatureClaude Code·Opus 4.8·3 steps](/content/gh/entireio/cli/session/897809d4-ecab-4dc6-aa21-97661cb62607#timeline-487abe46ddad/index.html)

## Changes

2

- cmd/entire/cli/importclaude
  
  - Adiscover.go+59
  
  - Adiscover\_test.go+55

```
package importclaude

import (
	"fmt"
	"os"
	"path/filepath"
	"slices"
	"strings"
	"time"

"github.com/entireio/cli/cmd/entire/cli/agent/claudecode"
)

// LookbackDays bounds how far back import reaches. Fixed this pass (no --since).
const LookbackDays = 30

// DiscoverSessions returns absolute paths of Claude transcript files for the
// repo modified within the lookback window. overridePath replaces the default
// ~/.claude/projects/<slug> dir. sessionFilter, when non-empty, keeps only
// files whose stem (name without .jsonl) matches one of the entries.
func DiscoverSessions(repoRoot, overridePath string, now time.Time, sessionFilter []string) ([]string, error) {
	dir := overridePath
	if dir == "" {
		ag := &claudecode.ClaudeCodeAgent{}
		d, err := ag.GetSessionDir(repoRoot)
		if err != nil {
			return nil, fmt.Errorf("resolve claude session dir: %w", err)
		}
		dir = d
	}
	entries, err := os.ReadDir(dir)
	if err != nil {
		if os.IsNotExist(err) {
			return nil, nil // no transcripts for this repo
		}
		return nil, fmt.Errorf("read claude session dir: %w", err)
	}
	cutoff := now.AddDate(0, 0, -LookbackDays)
	var out []string
	for _, e := range entries {
		if e.IsDir() || !strings.HasSuffix(e.Name(), ".jsonl") {
			continue
		}
		stem := strings.TrimSuffix(e.Name(), ".jsonl")
		if len(sessionFilter) > 0 && !slices.Contains(sessionFilter, stem) {
			continue
		}
		info, err := e.Info()
		if err != nil {
			continue
		}
		if info.ModTime().Before(cutoff) {
			continue
		}
		out = append(out, filepath.Join(dir, e.Name()))
	}
	slices.Sort(out)
	return out, nil
}
```

Acmd/entire/cli/importclaude/discover.go+59

```
package importclaude

import (
	"os"
	"path/filepath"
	"testing"
	"time"
)

func TestDiscoverSessions_LookbackAndFilter(t *testing.T) {
	t.Parallel()
	dir := t.TempDir()
	now := time.Date(2026, 6, 25, 12, 0, 0, 0, time.UTC)
	writeAged := func(name string, age time.Duration) {
		p := filepath.Join(dir, name)
		if err := os.WriteFile(p, []byte("{}\n"), 0o644); err != nil {
			t.Fatal(err)
		}
		mt := now.Add(-age)
		if err := os.Chtimes(p, mt, mt); err != nil {
			t.Fatal(err)
		}
	}
	writeAged("recent.jsonl", 5*24*time.Hour)
	writeAged("old.jsonl", 60*24*time.Hour)
	writeAged("skip.txt", 1*time.Hour)

got, err := DiscoverSessions("", dir, now, nil)
	if err != nil {
		t.Fatal(err)
	}
	if len(got) != 1 || filepath.Base(got[0]) != "recent.jsonl" {
		t.Fatalf("lookback filter wrong: %v", got)
	}

writeAged("abc123.jsonl", 1*24*time.Hour)
	got, err = DiscoverSessions("", dir, now, []string{"abc123"})
	if err != nil {
		t.Fatal(err)
	}
	if len(got) != 1 || filepath.Base(got[0]) != "abc123.jsonl" {
		t.Fatalf("session filter wrong: %v", got)
	}
}

func TestDiscoverSessions_MissingDirIsEmpty(t *testing.T) {
	t.Parallel()
	got, err := DiscoverSessions("", filepath.Join(t.TempDir(), "does-not-exist"), time.Now(), nil)
	if err != nil {
		t.Fatalf("missing dir should not error: %v", err)
	}
	if len(got) != 0 {
		t.Fatalf("expected empty, got %v", got)
	}
}
```

Acmd/entire/cli/importclaude/discover_test.go+55
