{"id":34979213,"url":"https://github.com/shuntaka9576/chathist","last_synced_at":"2026-04-09T02:09:41.767Z","repository":{"id":329658715,"uuid":"1120352905","full_name":"shuntaka9576/chathist","owner":"shuntaka9576","description":"📜 A lightweight CLI tool to view and export your AI coding agent's chat history.","archived":false,"fork":false,"pushed_at":"2026-04-09T01:14:45.000Z","size":1992,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-09T01:23:27.946Z","etag":null,"topics":["ai-agents","chat","claude","claude-code"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/shuntaka9576.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-21T02:57:23.000Z","updated_at":"2026-04-09T01:14:23.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/shuntaka9576/chathist","commit_stats":null,"previous_names":["shuntaka9576/chathist"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/shuntaka9576/chathist","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntaka9576%2Fchathist","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntaka9576%2Fchathist/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntaka9576%2Fchathist/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntaka9576%2Fchathist/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shuntaka9576","download_url":"https://codeload.github.com/shuntaka9576/chathist/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shuntaka9576%2Fchathist/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31581864,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-08T14:31:17.711Z","status":"online","status_checked_at":"2026-04-09T02:00:06.848Z","response_time":112,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["ai-agents","chat","claude","claude-code"],"created_at":"2025-12-27T00:51:45.222Z","updated_at":"2026-04-09T02:09:41.759Z","avatar_url":"https://github.com/shuntaka9576.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"# chathist\n\nA lightweight CLI tool to view and export your AI coding agent's chat history—currently optimized for Claude Code.\n\nBuilt for speed and flexibility, chathist hooks into fzf / fzf-tmux to let you breeze through past sessions with instant previews. It’s fully customizable via Lua configuration and Jinja2 templates, so you can tailor the output to your exact workflow.\n\n![img](asset/chathist-demo.gif)\n\n## Installation\n\n### Brew (MacOS)\n\n```bash\nbrew install shuntaka9576/tap/chathist\n```\n\n### Cargo (git)\n```bash\ngit clone https://github.com/shuntaka9576/chathist\ncd chathist\ncargo install --path .\n```\n\n## Getting Started\n\n`chathist` is designed to pair perfectly with `fzf`.\n\n`chathist list` appends normalized conversation text as an extra tab-separated field, so you can search by message body with `fzf` while keeping the session ID in the first column for previews and selection.\n\n### Zsh Integration\n\nAdd this to your `.zshrc` to get a unified session picker on `Ctrl+H`.\n\n**Session picker keybindings (inside fzf)**\n\n| Key | Action |\n|-----|--------|\n| `Tab` | Multi-select sessions |\n| `Shift+Up/Down` | Scroll preview |\n| `Ctrl+S` | Switch to cross-worktree mode |\n| `Ctrl+D` | Switch back to current project |\n\nAfter selecting sessions, you choose an action.\n\n| Action | Description |\n|--------|-------------|\n| `resume` | Resume the session in Claude Code (`claude --resume`) |\n| `open` | Open in editor with a template |\n\n```bash\nfunction chathist-widget() {\n  local selection=$(chathist list | fzf-tmux --multi \\\n    --delimiter=$'\\t' \\\n    --with-nth=2.. \\\n    --header 'ctrl-s: cross-worktree / ctrl-d: current project' \\\n    --preview 'chathist pick {1} --stdout' \\\n    --preview-window 'right:45%:wrap' \\\n    --bind 'ctrl-s:reload(chathist list -w)+change-preview(chathist pick -w {1} --stdout)+change-header(cross-worktree | ctrl-d: current project)' \\\n    --bind 'ctrl-d:reload(chathist list)+change-preview(chathist pick {1} --stdout)+change-header(current project | ctrl-s: cross-worktree)' \\\n    | cut -f1)\n\n  [ -z \"$selection\" ] \u0026\u0026 { zle reset-prompt; return; }\n\n  local action=$(printf 'resume\\nopen' | fzf-tmux --prompt=\"Action: \")\n  [ -z \"$action\" ] \u0026\u0026 { zle reset-prompt; return; }\n\n  case \"$action\" in\n    resume)\n      local session_id=$(echo \"$selection\" | head -1)\n      chathist insert -w \"$session_id\" 2\u003e/dev/null\n      BUFFER=\"claude --resume $session_id\"\n      zle accept-line\n      return\n      ;;\n    open)\n      local template=$(chathist pick --list-templates | fzf-tmux --prompt=\"Template: \")\n      [ -z \"$template\" ] \u0026\u0026 { zle reset-prompt; return; }\n      echo \"$selection\" | chathist pick -w -t \"$template\"\n      ;;\n  esac\n\n  zle reset-prompt\n}\n\nzle -N chathist-widget\nbindkey \"^h\" chathist-widget\n```\n\n### Core Commands\n\n* `chathist list`: List all chat sessions.\n* `chathist list -w`: List sessions across all worktrees of the same repository.\n* `chathist pick \u003csession_id\u003e`: Opens the specified session in the editor.\n* `chathist pick --stdout \u003csession_id\u003e`: Dump content to terminal (ideal for `fzf` previews).\n* `chathist pick --template \u003cname\u003e \u003csession_id\u003e`: Use a predefined template.\n* `chathist pick --list-templates`: List available template names (for fzf integration).\n* `chathist pick -w \u003csession_id\u003e`: Pick from any worktree of the same repository.\n* `chathist insert -w \u003csession_id\u003e`: Copy a session from another worktree into the current project's log directory (enables `claude --resume`).\n\n## Configuration\n\nChathist looks for its configuration file at `~/.config/chathist/config.lua` by default. Run `chathist config` to open the file. If you want to use a different location, set the `CHATHIST_CONFIG_FILE_PATH` environment variable.\n\n* The app looks for an editor in this order: config.editor, $EDITOR, then vim.\n* Claude logs default to the following directories: $CLAUDE_CONFIG_DIR/projects/ or ~/.claude/projects/.\n\nThe Lua table below outlines the internal defaults. To customize your setup, simply override these values in your `config.lua`.\n\n```lua\nlocal chathist = require(\"chathist\")\n\nreturn {\n  -- editor = \"vim\",  -- Uses $EDITOR or vim if not set\n  commands = {\n    list = {\n      template = \"$session_id\\t$title:50\\t$relative_time:\u003e15\\t$message_count:\u003e5\",\n    },\n    pick = {\n      template = {\n        preset = {\n          standard = chathist.template.pick.standard,\n          github = chathist.template.pick.github,\n          [\"github-compact\"] = chathist.template.pick.github_compact,\n          slack = chathist.template.pick.slack,\n        },\n        default = \"standard\",\n        -- list_hidden = { \"github-compact\" },  -- Hide from --list-templates output\n      },\n    },\n  },\n}\n```\n\n### commands.list\n\nCustomize output by setting `commands.list.template` in your config.\n\n#### Syntax\n\n| Format | Description |\n|--------|-------------|\n| `$var` | Expand variable |\n| `$var:N` | Expand with width N (left-aligned, truncated if longer) |\n| `$var:\u003eN` | Expand with width N (right-aligned) |\n\n#### Available Variables\n\n| Variable | Description |\n|----------|-------------|\n| `$session_id` | Session ID |\n| `$title` | Session title (first message or summary) |\n| `$time` | Timestamp |\n| `$relative_time` | Relative time (e.g., \"2 hours ago\") |\n| `$message_count` | Number of messages in the session |\n| `$branch` | Git branch |\n\n### commands.pick\n\nTemplates use Jinja2 syntax (via minijinja). Customize output by setting `commands.pick.template` in your config.\n\n#### Available Variables\n\n| Variable | Description |\n|----------|-------------|\n| `sessions` | Array of sessions |\n| `sessions[].id` | Session ID |\n| `sessions[].messages` | Array of messages |\n| `sessions[].messages[].role` | `\"user\"` or `\"assistant\"` |\n| `sessions[].messages[].content` | Message content |\n| `sessions[].plan` | Plan content (if exists) |\n\n\n#### Available Filters\n\n| Filter | Description |\n|--------|-------------|\n| `title` | Capitalize first letter (e.g., `\"user\"` → `\"User\"`) |\n| `truncate(length=N)` | Truncate string with `...` suffix |\n| `replace` | String replacement |\n\n#### Template Examples\n\n| Template | Description |\n|----------|-------------|\n| [standard](src/config/templates/pick/standard.j2) | Plain Markdown |\n| [github](src/config/templates/pick/github.j2) | Markdown wrapped in `\u003cdetails\u003e` for GitHub |\n| [github-compact](src/config/templates/pick/github_compact.j2) | Fully nested `\u003cdetails\u003e` for GitHub |\n| [slack](src/config/templates/pick/slack.j2) | Slack mrkdwn format (paste directly into Slack) |\n\nUse Jinja2 conditionals to filter messages by role.\n\n```jinja2\n{% for message in session.messages %}\n{% if message.role == \"user\" %}\n## User\n\n{{ message.content }}\n\n{% endif %}\n{% endfor %}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuntaka9576%2Fchathist","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshuntaka9576%2Fchathist","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshuntaka9576%2Fchathist/lists"}