{"id":34979190,"url":"https://github.com/angristan/fast-resume","last_synced_at":"2026-02-04T20:08:21.369Z","repository":{"id":330213739,"uuid":"1119435907","full_name":"angristan/fast-resume","owner":"angristan","description":"Find that one coding agent session you want to get back to!","archived":false,"fork":false,"pushed_at":"2026-01-20T21:48:53.000Z","size":568,"stargazers_count":18,"open_issues_count":1,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-01-21T07:20:18.748Z","etag":null,"topics":["agent-cli","claude-code","codex-cli","coding-agent","opencode","tantivy","textual"],"latest_commit_sha":null,"homepage":"https://stanislas.blog/2026/01/tui-index-search-coding-agent-sessions/","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/angristan.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-19T09:13:24.000Z","updated_at":"2026-01-20T21:48:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/angristan/fast-resume","commit_stats":null,"previous_names":["angristan/fast-resume"],"tags_count":35,"template":false,"template_full_name":null,"purl":"pkg:github/angristan/fast-resume","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angristan%2Ffast-resume","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angristan%2Ffast-resume/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angristan%2Ffast-resume/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angristan%2Ffast-resume/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/angristan","download_url":"https://codeload.github.com/angristan/fast-resume/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/angristan%2Ffast-resume/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29094729,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-04T19:16:55.479Z","status":"ssl_error","status_checked_at":"2026-02-04T19:16:52.508Z","response_time":62,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agent-cli","claude-code","codex-cli","coding-agent","opencode","tantivy","textual"],"created_at":"2025-12-27T00:51:42.138Z","updated_at":"2026-02-04T20:08:21.326Z","avatar_url":"https://github.com/angristan.png","language":"Python","funding_links":[],"categories":["Table of Contents"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.png\" alt=\"fast-resume\" width=\"120\" height=\"120\"\u003e\n\u003c/p\u003e\n\n# fast-resume\n\n[![PyPI version](https://img.shields.io/pypi/v/fast-resume)](https://pypi.org/project/fast-resume/)\n[![PyPI downloads](https://img.shields.io/pypi/dm/fast-resume)](https://pypi.org/project/fast-resume/)\n\nSearch and resume conversations across Claude Code, Codex, and more, all from a single place.\n\n## Why fast-resume?\n\nCoding agents are really good right now, so I'm using a bunch of them. Sometimes I remember I, or the LLM, mentioned something specific in a previous session, and I want to go back to it.\n\nThe problem is that currently, agents do have a resume feature, but either they don't support searching, or the search is very basic (e.g., title only).\n\nThat's why I built `fast-resume`: a command-line tool that aggregates all your coding agent sessions into a single searchable index, so you can quickly find and resume any session.\n\n![demo](https://github.com/user-attachments/assets/5ea9c2a5-a7c0-41bf-9357-394aeaaa0a06)\n\n## Features\n\n- **Unified Search**: One search box to find sessions across all your coding agents\n- **Full-Text Search**: Search not just titles, but the entire conversation content (user messages and assistant responses)\n- **Very fast**: Built on the Rust-powered Tantivy search engine for blazing-fast indexing and searching\n- **Fuzzy Matching**: Typo-tolerant search with smart ranking (exact matches boosted)\n- **Direct Resume**: Select, Enter, you're back in your session\n- **Beautiful TUI**: fzf-style interface with agent icons, color-coded results, and live preview\n- **Update Notifications**: Get notified when a new version is available\n\n## Supported Agents\n\n| Agent               | Data Location                                 | Resume Command                  |\n| ------------------- | --------------------------------------------- | ------------------------------- |\n| **Claude Code**     | `~/.claude/projects/`                         | `claude --resume \u003cid\u003e`          |\n| **Codex CLI**       | `~/.codex/sessions/`                          | `codex resume \u003cid\u003e`             |\n| **Copilot CLI**     | `~/.copilot/session-state/`                   | `copilot --resume \u003cid\u003e`         |\n| **VS Code Copilot** | `~/Library/Application Support/Code/` (macOS) | `code \u003cdirectory\u003e`              |\n| **Crush**           | `~/.local/share/crush/projects.json`          | _(interactive only)_            |\n| **OpenCode**        | `~/.local/share/opencode/storage/`            | `opencode \u003cdir\u003e --session \u003cid\u003e` |\n| **Vibe**            | `~/.vibe/logs/session/`                       | `vibe --resume \u003cid\u003e`            |\n\n## Installation\n\n```bash\n# Run directly (no install needed)\nuvx --from fast-resume fr\n\n# Or install permanently\nuv tool install fast-resume\nfr\n```\n\n## Usage\n\n### Interactive TUI\n\n```bash\n# Open the TUI with all sessions\nfr\n\n# Pre-filter search query\nfr \"authentication bug\"\n\n# Filter by agent\nfr -a claude\nfr -a codex\n\n# Filter by directory\nfr -d myproject\n\n# Combine filters\nfr -a claude -d backend \"api error\"\n```\n\n### Keyword Search Syntax\n\nFilter directly in the search box using keywords:\n\n```bash\nagent:claude             # Filter by agent\nagent:claude,codex       # Multiple agents (OR)\n-agent:vibe              # Exclude agent\nagent:claude,!codex      # Include claude, exclude codex\n\ndir:myproject            # Filter by directory (substring)\ndir:backend,!test        # Include backend, exclude test\n\ndate:today               # Sessions from today\ndate:yesterday           # Sessions from yesterday\ndate:\u003c1h                 # Within the last hour\ndate:\u003c2d                 # Within the last 2 days\ndate:\u003e1w                 # Older than 1 week\ndate:week                # Within the last week\ndate:month               # Within the last month\n```\n\nCombine keywords with free-text search:\n\n```bash\nfr \"agent:claude date:\u003c1d api bug\"\nfr \"dir:backend -agent:vibe auth\"\n```\n\n**Autocomplete**: Type `agent:cl` and press `Tab` to complete to `agent:claude`.\n\n### Non-Interactive Mode\n\n```bash\n# List sessions in terminal (no TUI)\nfr --no-tui\n\n# Just list, don't offer to resume\nfr --list\n\n# Force rebuild the index\nfr --rebuild\n\n# View your usage statistics\nfr --stats\n```\n\n### Yolo Mode\n\nResume sessions with auto-approve / skip-permissions flags:\n\n| Agent           | Flag Added                                   | Auto-detected |\n| --------------- | -------------------------------------------- | ------------- |\n| Claude          | `--dangerously-skip-permissions`             | No            |\n| Codex           | `--dangerously-bypass-approvals-and-sandbox` | Yes           |\n| Copilot CLI     | `--allow-all-tools --allow-all-paths`        | No            |\n| Vibe            | `--auto-approve`                             | Yes           |\n| OpenCode        | _(config-based)_                             | —             |\n| Crush           | _(no CLI resume)_                            | —             |\n| VS Code Copilot | _(n/a)_                                      | —             |\n\n**Auto-detection:** Codex and Vibe store the permissions mode in their session files. Sessions originally started in yolo mode are automatically resumed in yolo mode.\n\n**Interactive prompt:** For agents that support yolo but don't store it (Claude, Copilot CLI), you'll see a modal asking whether to resume in yolo mode. Use Tab to toggle, Enter to confirm.\n\n**Force yolo:** Use `fr --yolo` to skip the prompt and always resume in yolo mode, if supported.\n\n### Command Reference\n\n```\nUsage: fr [OPTIONS] [QUERY]\n\nArguments:\n  QUERY                    Search query (optional)\n\nOptions:\n  -a, --agent [claude|codex|copilot-cli|copilot-vscode|crush|opencode|vibe]\n                          Filter by agent\n  -d, --directory TEXT    Filter by directory (substring match)\n  --no-tui                Output list to stdout instead of TUI\n  --list                  Just list sessions, don't resume\n  --rebuild               Force rebuild the session index\n  --stats                 Show index statistics\n  --yolo                  Resume with auto-approve/skip-permissions flags\n  --version               Show version\n  --help                  Show this message and exit\n```\n\n## Keybindings\n\n### Navigation\n\n| Key                     | Action                             |\n| ----------------------- | ---------------------------------- |\n| `↑` / `↓`               | Move selection up/down             |\n| `j` / `k`               | Move selection up/down (vim-style) |\n| `Page Up` / `Page Down` | Move by 10 rows                    |\n| `Enter`                 | Resume selected session            |\n| `/`                     | Focus search input                 |\n\n### Preview \u0026 Actions\n\n| Key       | Action                                |\n| --------- | ------------------------------------- |\n| `Ctrl+\\`` | Toggle preview pane                   |\n| `+` / `-` | Resize preview pane                   |\n| `Tab`     | Accept autocomplete suggestion        |\n| `c`       | Copy full resume command to clipboard |\n| `Ctrl+P`  | Open command palette                  |\n| `q`/`Esc` | Quit                                  |\n\n### Yolo Mode Modal\n\n| Key             | Action            |\n| --------------- | ----------------- |\n| `Tab` / `←` `→` | Toggle selection  |\n| `Enter`         | Confirm selection |\n| `y`             | Select Yolo       |\n| `n`             | Select No         |\n| `Esc`           | Cancel            |\n\n## Statistics Dashboard\n\nRun `fr --stats` to see analytics about your coding sessions:\n\n```\nIndex Statistics\n\n  Total sessions          751\n  Total messages          13,799\n  Avg messages/session    18.4\n  Index size              15.5 MB\n  Index location          ~/.cache/fast-resume/tantivy_index\n  Date range              2023-11-15 to 2025-12-22\n\nData by Agent\n\n┌────────────────┬───────┬──────────┬──────────┬──────────┬──────────┬─────────────┐\n│ Agent          │ Files │     Disk │ Sessions │ Messages │  Content │ Data Dir    │\n├────────────────┼───────┼──────────┼──────────┼──────────┼──────────┼─────────────┤\n│ claude         │   477 │ 312.9 MB │      377 │   10,415 │   3.1 MB │ ~/.claude/… │\n│ copilot-vscode │   191 │ 146.0 MB │      189 │      954 │   1.4 MB │ ~/Library/… │\n│ codex          │   107 │  23.6 MB │       89 │      321 │ 890.6 kB │ ~/.codex/…  │\n│ opencode       │  9275 │  46.3 MB │       72 │    1,912 │ 597.7 kB │ ~/.local/…  │\n│ vibe           │    12 │ 858.2 kB │       12 │      138 │ 380.0 kB │ ~/.vibe/…   │\n│ crush          │     3 │   1.0 MB │        7 │       44 │  15.2 kB │ ~/.local/…  │\n│ copilot-cli    │     5 │ 417.1 kB │        5 │       15 │   6.9 kB │ ~/.copilot… │\n└────────────────┴───────┴──────────┴──────────┴──────────┴──────────┴─────────────┘\n\nActivity by Day\n\n Mon   ██████████              89\n Tue   ██████████              86\n Wed   █████                   44\n Thu   ██████████████         115\n Fri   █████████████          112\n Sat   ████████████████████   163\n Sun   █████████████████      142\n\nActivity by Hour\n\n  0h ▄▁        ▄▄▅▂▂▂▂▂▃▃▃▅▅█ 23h\n  Peak hours: 23:00 (99), 22:00 (63), 12:00 (63)\n\nTop Directories\n\n┌───────────────────────┬──────────┬──────────┐\n│ Directory             │ Sessions │ Messages │\n├───────────────────────┼──────────┼──────────┤\n│ ~/git/openvpn-install │      234 │    5,597 │\n│ ~/lab/larafeed        │      158 │    2,590 │\n│ ~/lab/fast-resume     │       81 │    2,027 │\n│ ...                   │          │          │\n└───────────────────────┴──────────┴──────────┘\n```\n\n## How It Works\n\n### Architecture\n\n```\n┌────────────────────────────────────────────────────────────────────────────────────────┐\n│                                 SessionSearch                                          │\n│                                                                                        │\n│   • Orchestrates adapters in parallel (ThreadPoolExecutor)                             │\n│   • Compares file mtimes to detect changes (incremental updates)                       │\n│   • Delegates search queries to Tantivy index                                          │\n└────────────────────────────────────────────────────────────────────────────────────────┘\n                      │                                       │\n         ┌────────────┴────────────┐                          │\n         ▼                         ▼                          ▼\n┌──────────────────┐    ┌───────────────────────────────────────────────────────────────────────────────┐\n│  TantivyIndex    │    │                                 Adapters                                       │\n│                  │    │  ┌────────┐ ┌───────┐ ┌───────┐ ┌─────────┐ ┌───────┐ ┌────────┐ ┌────┐        │\n│ • Fuzzy search   │◄───│  │ Claude │ │ Codex │ │Copilot│ │ Copilot │ │ Crush │ │OpenCode│ │Vibe│        │\n│ • mtime tracking │    │  │        │ │       │ │  CLI  │ │ VS Code │ │       │ │        │ │    │        │\n│                  │    │  └───┬────┘ └───┬───┘ └───┬───┘ └────┬────┘ └───┬───┘ └───┬────┘ └─┬──┘        │\n│ ~/.cache/        │    │      │          │         │          │          │         │        │           │\n│   fast-resume/   │    └──────┼──────────┼─────────┼──────────┼──────────┼─────────┼────────┼───────────┘\n└──────────────────┘           ▼          ▼         ▼          ▼          ▼         ▼        ▼\n                          ~/.claude/ ~/.codex/ ~/.copilot/  VS Code/   crush.db opencode/ ~/.vibe/\n```\n\n### Session Parsing\n\nEach agent stores sessions differently. Adapters normalize them into a common `Session` structure:\n\n| Agent          | Format                                               | Parsing Strategy                                                                            |\n| -------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------- |\n| Claude Code    | JSONL in `~/.claude/projects/\u003cproject\u003e/*.jsonl`      | Stream line-by-line, extract `user`/`assistant` messages, skip `agent-*` subprocess files   |\n| Codex          | JSONL in `~/.codex/sessions/**/*.jsonl`              | Line-by-line parsing, extract from `session_meta`, `response_item`, and `event_msg` entries |\n| Copilot CLI    | JSONL in `~/.copilot/session-state/*.jsonl`          | Line-by-line parsing, extract `user.message` and `assistant.message` types                  |\n| Copilot VSCode | JSON in VS Code's `workspaceStorage/*/chatSessions/` | Parse `requests` array with message text and response values                                |\n| Crush          | SQLite DB at `\u003cproject\u003e/crush.db`                    | Query `sessions` and `messages` tables directly, parse JSON `parts` column                  |\n| OpenCode       | Split JSON in `~/.local/share/opencode/storage/`     | Lazy-load `message/` and `part/` per session for progressive indexing                       |\n| Vibe           | JSON in `~/.vibe/logs/session/session_*.json`        | Parse `messages` array with role-based content                                              |\n\n**The normalized Session structure:**\n\n```python\n@dataclass\nclass Session:\n    id: str              # Unique identifier (usually filename or UUID)\n    agent: str           # \"claude\", \"codex\", \"copilot-cli\", \"copilot-vscode\", \"crush\", \"opencode\", \"vibe\"\n    title: str           # Summary or first user message (max 100 chars)\n    directory: str       # Working directory where session was created\n    timestamp: datetime  # Last modified time\n    preview: str         # First 500 chars for preview pane\n    content: str         # Full conversation text (» user, ␣␣ assistant)\n    message_count: int   # Conversation turns (user + assistant, excludes tool results)\n    mtime: float         # File mtime for incremental update detection\n```\n\n**What gets indexed:**\n\n- User text messages (the actual prompts you typed)\n- Assistant text responses\n\n**What's excluded from indexing:**\n\n- Tool results (file contents, command outputs, API responses)\n- Tool use/calls (function invocations)\n- Meta messages (system prompts, context summaries)\n- Local command outputs (slash commands like `/context`)\n\nThis keeps the index focused on the actual conversation and avoids bloating it with large tool outputs that are rarely useful for search.\n\n### Indexing\n\n**Incremental updates** avoid re-parsing on every launch:\n\n1. Load known sessions from Tantivy index with their `mtime` values\n2. Scan session files, compare mtimes against known values\n3. Only parse files where `current_mtime \u003e known_mtime + 0.001`\n4. Detect deleted sessions (in index but not on disk)\n5. Apply changes atomically: delete removed, upsert modified\n\n**Progressive indexing** with batched commits:\n\n```python\ndef handle_session(session):\n    # Buffer session for batched indexing\n    pending_sessions.append(session)\n    if len(pending_sessions) \u003e= BATCH_SIZE:\n        self._index.update_sessions(pending_sessions)  # Batch commit\n        pending_sessions.clear()\n        on_progress()  # TUI updates\n\n# Adapters call on_session as each session is parsed\nadapter.find_sessions_incremental(known, on_session=handle_session)\n```\n\nSessions appear in the TUI progressively as they're parsed and batched. OpenCode uses parallel file I/O and processes smaller sessions first for faster initial results.\n\n**Schema versioning**: A `.schema_version` file tracks the index schema. If it doesn't match the code's `SCHEMA_VERSION` constant, the entire index is deleted and rebuilt. This prevents deserialization errors after upgrades.\n\n### Search\n\n[Tantivy](https://github.com/quickwit-oss/tantivy) is a Rust full-text search library (powers Quickwit, similar to Lucene). We use it via [tantivy-py](https://github.com/quickwit-oss/tantivy-py).\n\n**Hybrid search** combines exact and fuzzy matching for best results:\n\n```python\n# Exact match (boosted 5x) - uses BM25 scoring\nexact_query = index.parse_query(query, [\"title\", \"content\"])\nboosted_exact = tantivy.Query.boost_query(exact_query, 5.0)\n\n# Fuzzy match (edit distance 1) - for typo tolerance\nfor term in query.split():\n    fuzzy_title = tantivy.Query.fuzzy_term_query(schema, \"title\", term, distance=1, prefix=True)\n    fuzzy_content = tantivy.Query.fuzzy_term_query(schema, \"content\", term, distance=1, prefix=True)\n    ...\n\n# Combine: exact OR fuzzy (exact scores higher due to boost)\ntantivy.Query.boolean_query([\n    (tantivy.Occur.Should, boosted_exact),\n    (tantivy.Occur.Should, fuzzy_query),\n])\n```\n\nThis ensures exact matches rank first while still finding typos like `auth midleware` → \"authentication middleware\".\n\n**Query lifecycle:**\n\n```\n┌─────────────┐   50ms    ┌─────────────┐  background  ┌─────────────┐\n│  Keystroke  │ ────────► │  Debounce   │ ───────────► │   Worker    │\n└─────────────┘  timer    └─────────────┘   thread     └──────┬──────┘\n                                                              │\n                          ┌─────────────┐              ┌──────▼──────┐\n                          │   Render    │ ◄─────────── │   Tantivy   │\n                          │   Table     │   results    │    Query    │\n                          └─────────────┘              └─────────────┘\n```\n\n### TUI\n\n**Streaming results**: Sessions appear as each adapter completes, not after all finish.\n\n- **Fast path**: Index up-to-date → load synchronously, no spinner\n- **Slow path**: Changes detected → spinner, stream results via `on_progress()` callback\n\n**Preview context**: When searching, the preview pane jumps to the matching portion:\n\n```python\nfor term in query.lower().split():\n    pos = content.lower().find(term)\n    if pos != -1:\n        start = max(0, pos - 100)  # Show ~100 chars before match\n        preview_text = content[start:start + 1500]\n        break\n```\n\nMatching terms are highlighted with Rich's `Text.stylize()`.\n\n### Resume Handoff\n\nWhen you press Enter on a session, fast-resume hands off to the original agent:\n\n```python\n# In cli.py after TUI exits\nresume_cmd, resume_dir = run_tui(query=query, agent_filter=agent)\n\nif resume_cmd:\n    # 1. Change to the session's original working directory\n    os.chdir(resume_dir)\n\n    # 2. Replace current process with agent's resume command\n    os.execvp(resume_cmd[0], resume_cmd)\n```\n\n`os.execvp()` replaces the Python process entirely with the agent CLI. This means:\n\n- No subprocess overhead\n- Shell history shows `claude --resume xyz`, not `fr`\n- Agent inherits the correct working directory\n- fast-resume process is gone after handoff\n\nEach adapter returns the appropriate command:\n\n| Agent          | Resume Command                  | With `--yolo`                                                  |\n| -------------- | ------------------------------- | -------------------------------------------------------------- |\n| Claude         | `claude --resume \u003cid\u003e`          | `claude --dangerously-skip-permissions --resume \u003cid\u003e`          |\n| Codex          | `codex resume \u003cid\u003e`             | `codex --dangerously-bypass-approvals-and-sandbox resume \u003cid\u003e` |\n| Copilot CLI    | `copilot --resume \u003cid\u003e`         | `copilot --allow-all-tools --allow-all-paths --resume \u003cid\u003e`    |\n| Copilot VSCode | `code \u003cdirectory\u003e`              | _(no change)_                                                  |\n| OpenCode       | `opencode \u003cdir\u003e --session \u003cid\u003e` | _(no change)_                                                  |\n| Vibe           | `vibe --resume \u003cid\u003e`            | `vibe --auto-approve --resume \u003cid\u003e`                            |\n| Crush          | `crush`                         | _(no change)_                                                  |\n\n### Performance\n\nWhy fast-resume feels instant:\n\n- **Tantivy (Rust)**: Search engine written in Rust, accessed via Python bindings. Handles fuzzy queries over 10k+ sessions in \u003c10ms\n- **Incremental updates**: Only re-parse files where `mtime` changed. Second launch with no changes: ~50ms total\n- **Parallel adapters**: All adapters run simultaneously in ThreadPoolExecutor. Total time = slowest adapter, not sum\n- **Debounced search**: 50ms debounce prevents wasteful searches while typing\n- **Background workers**: Search runs in thread, UI never blocks\n- **orjson**: Rust-based JSON parsing, ~10x faster than stdlib json\n- **Streaming results**: Sessions appear as each adapter completes, not after all finish\n\nTypical performance on a machine with ~500 sessions:\n\n- Cold start (empty index): ~2s\n- Warm start (no changes): ~50ms\n- Search query: \u003c10ms\n\n## Development\n\n```bash\n# Clone and setup\ngit clone https://github.com/angristan/fast-resume.git\ncd fast-resume\nuv sync\n\n# Run locally\nuv run fr\n\n# Install pre-commit hooks\nuv run pre-commit install\n\n# Run tests\nuv run pytest -v\n\n# Lint and format\nuv run ruff check .\nuv run ruff format .\n```\n\n### Project Structure\n\n```\nfast-resume/\n├── src/fast_resume/\n│   ├── cli.py              # Click CLI entry point\n│   ├── config.py           # Constants, colors, paths\n│   ├── index.py            # TantivyIndex - search engine\n│   ├── search.py           # SessionSearch - adapter orchestration\n│   ├── tui.py              # Textual TUI application\n│   ├── assets/             # Agent icons (PNG)\n│   └── adapters/\n│       ├── base.py         # Session dataclass, AgentAdapter protocol\n│       ├── claude.py       # Claude Code adapter\n│       ├── codex.py        # Codex CLI adapter\n│       ├── copilot.py      # GitHub Copilot CLI adapter\n│       ├── copilot_vscode.py # VS Code Copilot Chat adapter\n│       ├── crush.py        # Crush adapter\n│       ├── opencode.py     # OpenCode adapter\n│       └── vibe.py         # Vibe adapter\n├── tests/                  # pytest test suite\n├── pyproject.toml          # Dependencies and build config\n└── README.md\n```\n\n### Tech Stack\n\n| Component           | Library                                                             |\n| ------------------- | ------------------------------------------------------------------- |\n| TUI Framework       | [Textual](https://textual.textualize.io/)                           |\n| Terminal Formatting | [Rich](https://rich.readthedocs.io/)                                |\n| CLI Framework       | [Click](https://click.palletsprojects.com/)                         |\n| Search Engine       | [Tantivy](https://github.com/quickwit-oss/tantivy) (via tantivy-py) |\n| JSON Parsing        | [orjson](https://github.com/ijl/orjson) (fast)                      |\n| Date Formatting     | [humanize](https://python-humanize.readthedocs.io/)                 |\n\n## Configuration\n\nfast-resume uses sensible defaults and requires no configuration.\n\nTo clear the index and rebuild from scratch:\n\n```bash\nrm -rf ~/.cache/fast-resume/\nfr --rebuild\n```\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangristan%2Ffast-resume","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fangristan%2Ffast-resume","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fangristan%2Ffast-resume/lists"}