Skip to content
nihenPublic

About

Agent History — search and browse AI coding agent sessions (Claude, Codex, Gemini, Copilot, Cursor) from a single CLI

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

49 Commits

Folders and files

Repository files navigation

Agent History (ah)

Agent History — search, inspect, and resume coding-agent sessions from a single CLI.

ah discovers session files from Claude Code, Codex, Gemini CLI, Cursor, GitHub Copilot CLI, Antigravity CLI (agy), Grok CLI (grok), and opencode (opencode). It works with zero config, defaults to the current directory, and gives you one place to search, inspect, and resume past work.

Read-only by default. ah works directly on agent session files, lets you search and inspect them, and only executes when you explicitly run resume.

Demo

Demo

Quick Look

On a TTY, ah log outputs in git log style with auto-pager. Defaults to current directory:

$ ah log
session a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6
Agent:    claude
Project:  my-webapp
Cwd:      /home/user/src/my-webapp
Date:     2026-03-23 14:00 - 2026-03-23 18:00

    implement OAuth2 authentication flow

session e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b
Agent:    cursor
Project:  my-webapp
Cwd:      /home/user/src/my-webapp
Date:     2026-03-23 12:15 - 2026-03-23 14:22

    fix memory leak in worker pool

Pick a session ID from the log and resume it — ah launches the original agent's resume command (e.g. claude --resume):

$ ah resume a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6

Want the exact command first without executing anything?

$ ah resume --print a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6
cd '/home/user/src/my-webapp' && 'claude' '--resume' 'a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6'

Or browse and filter sessions with -i (via fzf or compatible finder, with transcript preview):

$ ah resume -i

Full-text search across all directories (piped output is plain TSV). -q searches the conversation — user and assistant messages plus tool calls (commands, arguments, file paths) and tool output — not JSON keys or injected instructions. Use -p to search only your prompts, or --raw-search to match the raw session files including metadata:

$ ah log -a -q "OAuth" | head -3
claude  my-webapp    2026-03-23 18:00  implement OAuth2 authentication flow  ...implement OAuth2 auth...          a1b2c3d4-5e6f-7a8b-9c0d-e1f2a3b4c5d6
cursor  my-webapp    2026-03-23 14:22  fix memory leak in worker pool        ...reviewing the OAuth token...      e5f6a7b8-9c0d-1e2f-3a4b-5c6d7e8f9a0b
codex   api-server   2026-03-22 11:30  add Redis caching layer              ...cache OAuth tokens with 1h TTL... sess_7e8f9a0b1c2d3e4f5a6b7c8d9e0f1a2b

Find the actual passages instead of just the sessions:

ah search 'OAuth'                 # every occurrence in the current directory
ah search 'OAuth' -a --json       # JSON Lines across all directories
ah search '認証' -p                # user prompts only
ah search 'error' --max-matches 20
ah search 'OAuth' --verbose       # full log paths and match positions on TTY
ah search 'OAuth' --kind user,assistant  # conversation text only
ah search 'error' --kind tool-output    # tool results only
ah search 'OAuth' -i              # pick a hit, preview context, Enter to show

log -q returns one row per session with its first matching excerpt. search returns one row per non-overlapping regex occurrence, including multiple occurrences in a single message and matches in tool input/output. It uses the same case-insensitive regex and content extraction as log -q. No index or external search service is required.

On a terminal, passages are grouped by session with an automatic pager. Like rg --heading or git grep --heading --break, the default display puts one heading above each group of passages and a blank line between sessions. Session headings are cyan and bold, titles are bold, and dates are dim. Each passage appears on its own indented line with a structural kind label (user, assistant, tool-input, tool-output, or unknown), with the current occurrence highlighted in bold yellow. Full log paths and position labels are omitted by default so the passages stay compact. Remote session headings keep a remote:NAME label to distinguish hosts.

Use -v / --verbose to show the full log path and a dim position line before each passage. Positions are labeled text #N bytes START..END: text #N is a search-fragment index, not a transcript line number. Verbose output also includes an opaque at POSITION token and separates passages with blank lines. This flag only affects terminal output; JSON/TSV retain all their existing fields and formatting.

If a match is clipped by the snippet limit, only its visible portion is highlighted. --no-color and NO_COLOR disable styling; NO_COLOR takes precedence over --color, as with other commands. JSON/TSV output never receives display colors. Piped output is TSV without a header, with these columns: path, agent, project, id, text_index, match_start, match_end, snippet, kind, position. Tabs, newlines, carriage returns, and backslashes are escaped as \t, \n, \r, and \\. JSON Lines contains the same fields plus modified_at and title, with numbers represented as JSON numbers.

  • text_index is a 1-based index of nonempty search fragments, counted before kind filtering. It is not a transcript message number. One tool call can yield several fragments. Use position, not this index, for navigation.
  • kind is derived from log structure, never inferred from the text. Ambiguous records remain unknown (for example, Antigravity's generic model records). --kind accepts a comma-separated union; the default includes every kind. -p is shorthand for --kind user and includes all user text parts, but not tool results stored in user-role containers. It cannot be combined with other kinds. log -p -q keeps its existing prompt extraction behavior.
  • position is an opaque versioned location within the session identified by path. It includes a fingerprint of the searchable source prefix. Do not construct it yourself. Filtering and snippet length do not change positions; appending records preserves them. An edited/reordered prefix requires a new search instead of silently opening a different occurrence.
  • match_start / match_end are 0-based UTF-8 byte offsets, with an exclusive end, in the decoded fragment (not the snippet or raw file).
  • Snippets contain at most --snippet-length Unicode characters (default 240), including ellipses. Even a match longer than the limit is truncated; offsets still describe the full match.
  • Sessions sort by modified_at descending, then path ascending for ties. Occurrences within a session follow source order. This is not relevance order or individual-message timestamp order.
  • --max-matches caps occurrences across all sessions and hosts (default 100; 0 means unlimited). -n still limits session files scanned, not results. The cap does not guarantee fewer files scanned; the existing session pipeline first finds candidates, then search enumerates their occurrences.
  • -a, -d, --agent, --project, --since, --until, --running, --no-archived, and --subagents retain their existing filtering semantics. --remote / -A run search on the remote host, which also needs this version of ah. Remote failures are errors, not silently incomplete results.
  • Supply either a positional pattern or -q, not both. Empty queries and invalid regexes are errors; no matches is success with empty output.
  • --raw-search remains available through log, not search.

Open an occurrence with context

ah show <session-id-or-path> --at <position-from-search> -C 2
ah search 'OAuth' -i

show --at displays the selected source record and, by default, two searchable records on either side. -C 0 displays only the selected record. A record is a message or tool event; it may contain multiple text/argument fragments. Context is not counted in lines and is not restricted by the search kind filter. Tool inputs and outputs are displayed even though ordinary show omits them. The selected fragment is marked >; its exact occurrence is highlighted when color is enabled. Zero-width occurrences select the fragment without coloring a character. JSON output with --at has record, fragment, kind, text, selected, match_start, and match_end (offsets are null on context fragments). Ordinary show and its existing JSON schema are unchanged.

search -i uses the existing selector setting (-s, $AH_SELECTOR, or fzf). The fzf/sk preview opens the same position with context; Enter displays it and Esc cancels. --no-preview disables the preview. Structured result formats (--json, --tsv) cannot be combined with -i. Remotes execute both search and position display on the host that owns the data; both hosts need this version.

Search output migration: kind and position are new JSON fields and are appended as TSV columns 9 and 10; existing columns remain in positions 1–8. text_index now counts nonempty fragments in the unfiltered stream, including with -p. Consumers requiring the previous eight-column schema should select those columns explicitly. -p now searches all user text parts, not just the legacy transcript reader's first/combined prompt representation.

Compatibility: search used to be a hidden alias for log. For the old session-list output and its field-selection options, use ah log explicitly.

Show a session transcript:

$ ah show a1b2c3d4
>>> implement OAuth2 authentication flow

I'll implement the OAuth2 flow. Let me start by reading the existing auth module...

Sessions grouped by project:

$ ah project -a
PROJECT      SESSION_COUNT  LAST_MODIFIED_AT  AGENTS
my-webapp    18             2026-03-23 18:00  claude, codex, cursor, gemini
api-server   14             2026-03-23 09:15  claude, codex, copilot, cursor
ml-pipeline  11             2026-03-22 08:50  claude, copilot, gemini
infra         5             2026-03-20 17:40  codex, cursor
docs          3             2026-03-19 11:25  claude, gemini

List agent memory and instruction files across all agents:

$ ah memory -a
AGENT   PROJECT    TYPE         NAME              MODIFIED_AT       DESCRIPTION
claude  my-webapp  feedback     always-run-tests  2026-03-23 18:00  Run test suite before committing
claude  my-webapp  instruction  CLAUDE.md         2026-03-22 10:00
shared  my-webapp  instruction  AGENTS.md         2026-03-21 15:30

A project-level AGENTS.md is read by several agents, so it is listed as shared and matches any --agent filter.

Files listed per agent (global paths honor each agent's env var; project paths are looked up in the current directory and, inside a git repository, every directory up to its root; -a does this for every known project):

Agent Global Project
Claude ~/.claude/CLAUDE.md, rules/**/*.md, agent-memory/*/*.md, auto memory projects/*/memory/*.md CLAUDE.md, CLAUDE.local.md, .claude/CLAUDE.md, .claude/rules/**/*.md, .claude/agent-memory{,-local}/*/*.md
Codex ~/.codex/AGENTS.md, AGENTS.override.md, memories/**/*.md AGENTS.override.md
Gemini ~/.gemini/GEMINI.md (or context.fileName in settings.json) same file names
Copilot ~/.copilot/copilot-instructions.md .github/copilot-instructions.md, .github/instructions/**/*.instructions.md
Cursor ~/.cursor/rules/**/*.mdc .cursorrules, .cursor/rules/**/*.mdc
Antigravity (agy) ~/.gemini/config/rules/*.md .agents/rules/*.md, .agent/rules/*.md
Grok ~/.grok/AGENTS.md, rules/*.md, memory/MEMORY.md, memory topics memory-v2/{global,workspaces/*}/topics/*.md .grok/rules/*.md
opencode ~/.config/opencode/AGENTS.md, instructions in opencode.json(c) instructions in opencode.json(c)
shared — AGENTS.md

Types: instruction (always-loaded files), rule, memory (or the type in a memory file's frontmatter, such as feedback), and skill. Skills (SKILL.md under skills/*/ of Claude, Codex, and agy, and .agents/skills/*/) are listed only with -t skill.

Show session summary per agent:

$ ah agent
AGENT     SESSIONS  LATEST
claude          50  2026-03-24 17:55
codex           42  2026-03-24 16:32
copilot         18  2026-03-23 19:00
cursor          12  2026-03-22 13:40
gemini           5  2026-03-21 10:50

Support Matrix

Agent List Search Show Resume Running Memory
Claude ✓ ✓ ✓ ✓ ✓ ✓
Codex ✓ ✓ ✓ ✓ ✓¹ ✓
Gemini ✓ ✓ ✓ ✓ ✓
Copilot ✓ ✓ ✓ ✓ ✓ ✓
Cursor ✓ ✓ ✓ ✓ ✓
Antigravity (agy) ✓ ✓ ✓ ✓ ✓
Grok ✓ ✓ ✓ ✓ ✓ ✓
opencode ✓ ✓ ✓ ✓ ✓

Running detection reads each agent's own bookkeeping: Claude's sessions/<pid>.json (checking procStart so a reused PID is not reported), Grok's active_sessions.json, Copilot's session-state/<id>/inuse.<pid>.lock, and Codex's thread-writer-locks/<id>.lock. ¹ Codex is detected on Linux only, from the kernel lock table (/proc/locks); its PID is the lock holder, which for the interactive TUI is the Codex app-server. Running detection needs a PID liveness check, which is not implemented on Windows.

Features

  • Cross-agent — one tool for 8 agents (see ah list-agents)
  • Zero-config — scans the standard session locations for each supported CLI
  • Fast — parallel file collection with rayon, regex search via memmap2, no subprocesses for search/parsing
  • Resume-friendly — ah resume and ah show can target the latest matching session without pasting IDs
  • Structured output — git log-style multi-line format with auto-pager on TTY, plain TSV when piped, plus --table, --json, --ltsv
  • Interactive — -i adds fuzzy selection with transcript preview (via fzf or compatible finder)

Installation

Homebrew

brew install nihen/tap/ah

Supported in the tap: macOS (Apple Silicon and Intel) and Linux (x86_64 and arm64).

Cargo

cargo install ah-cli

From binary

Download a prebuilt binary from GitHub Releases.

Available for macOS (arm64, x86_64) and Linux (x86_64, arm64). The Linux binaries are statically linked (musl).

From source

cargo install --git https://github.com/nihen/ah

Shell completion

# zsh
mkdir -p ~/.zfunc && ah completion zsh > ~/.zfunc/_ah
# Add to .zshrc: fpath=(~/.zfunc $fpath); autoload -Uz compinit && compinit

# bash
ah completion bash > ~/.local/share/bash-completion/completions/ah

# fish
ah completion fish > ~/.config/fish/completions/ah.fish

Tips

Interactive mode (-i)

Most commands support -i for fuzzy selection with transcript preview. Requires fzf or a compatible finder (e.g. sk) in PATH. Override with $AH_SELECTOR.

fzf compatibility:

  • Selection and transcript preview work with older fzf too, including 0.44 from Debian/Ubuntu apt.
  • Preview search (the query is highlighted in the preview and the preview scrolls to the first match; ctrl-s switches list filtering on and off) needs fzf 0.62 or newer. On older fzf it is turned off automatically. fzf 0.63+ calculates the scroll position in the background so typing stays responsive.

Useful as a shell function — pick a project, browse its sessions, resume:

ahr() { local d; d="$(ah project -i)" && ah resume -i -d "$d"; }

Command-line options

ah -h

Search, inspect, and resume coding-agent sessions from one CLI
(read-only except resume)

Defaults to the current directory. Use -a to search across all known sessions.

Usage:
  ah <COMMAND> [OPTIONS]

Commands:
  log                 List sessions
  search              Show matching passages
  project             List known projects
  show                Show session transcript
  resume              Resume an agent session
  memory              List agent memory and instruction files
  agent               Show session summary per agent

Help / setup:
  list-agents         List supported agents
  completion          Generate shell completion script
  man                 Generate man page

Global options:
  -a, --all               Show all sessions (disable default cwd filtering)
  -A                      Show all sessions including all configured remotes
  --agent <NAME>          Filter by agent name (e.g. claude, codex, gemini)
  --project <NAME>        Filter by project name
  -d, --dir <PATH>        Filter by working directory (default: current directory)
  -q, --query <REGEX>     Search messages and tool input/output (regex, case-insensitive)
  -p, --prompt-only       Search only user prompts (use with -q)
  --raw-search            Search raw session files incl. metadata (use with -q)
  -n, --limit N           Max session files to scan (default: 0, no limit)
  -i, --interactive       Interactive mode via fuzzy finder (fzf/sk)
  -s <CMD>                Override fuzzy selector (default: $AH_SELECTOR or fzf)
  --no-preview            Disable preview in interactive mode
  --interactive-display <FIELDS>  Override fuzzy selector display columns (log -i / show -i only)
  --running               Show only currently running sessions (Claude, Codex, Copilot, Grok)
  --no-archived           Hide sessions the agent has archived (Codex)
  --subagents             Include subagent sessions (spawned by another session)
  --remote <NAME>         Include sessions from remote host (requires ah on remote; see ~/.ahrc [remotes.*])
  --since <SPEC>          Show sessions newer than (e.g. "2026-03-20", "3d", "1w", "2m" = ~60 days)
  --until <SPEC>          Show sessions older than (e.g. "2026-03-20", "3d", "1w", "2m" = ~60 days)
  --color                 Force colored output (even through pipes)
  --no-color              Disable colored output
  --no-pager              Disable automatic pager
  -h, --help              Show this help
  -V, --version           Show version

Examples:
  ah log                      # latest sessions for the current directory
  ah log -a -q "auth"         # search across all known sessions
  ah log -A                   # all sessions including all remotes
  ah resume                   # resume the latest matching session
  ah show -q "OAuth"          # show the latest matching session
  ah resume -i                # browse sessions with fzf/sk and resume

Run `ah <COMMAND> --help` for subcommand-specific options.

Configuration:
  ~/.ahrc (TOML) — optional config file for agent customization and remote hosts.
  See https://github.com/nihen/ah#configuration-ahrc for details.

ah log --help

List sessions

Usage:
  ah log [OPTIONS]

Options:
  -o, --fields <FIELDS>   Select output fields (replaces defaults, see --list-fields)
                          Default: agent, project, modified_at, title, id
                          With -q: agent, project, modified_at, title, matched, id
  -O, --extra-fields <FIELDS>  Add fields to defaults (comma-separated)
  --table                 Aligned table with header row
  --tsv                   Tab-separated values (no header, no color)
  --ltsv                  Labeled Tab-Separated Values (in -i mode: selector display format)
  --json                  JSON Lines output
  -S, --sort <FIELD>      Sort by field (default: modified_at)
  --asc                   Sort ascending
  --desc                  Sort descending (default)
  --transcript-limit N    Max characters for transcript field (default: 500)
  --title-limit N         Max characters for auto-generated title (default: 50, 0 = no limit)
  -L, --list-fields       List available output fields and exit (use with --json for machine-readable output)

Default output (when no format flag is given):
  git-log style multi-line with auto-pager on TTY, plain TSV when piped

Interactive mode:
  -i, --interactive       Browse sessions via fuzzy finder; prints selected path
                          With -o: prints selected fields as TSV instead of path
  --interactive-display <FIELDS>  Override display columns in fuzzy finder
  -s <CMD>                Selector command (default: $AH_SELECTOR or fzf)
  --no-preview            Disable transcript preview (enabled by default for fzf, sk)

Global options are also available (see ah -h).

ah search --help

Show matching passages from conversations and tool input/output

Usage:
  ah search [OPTIONS] <PATTERN>
  ah search [OPTIONS] -q <REGEX>

Options:
  --json                  One JSON object per occurrence (JSON Lines)
  --tsv                   TSV without a header (default when piped)
  --kind <KINDS>          Comma-separated: user,assistant,tool-input,tool-output,unknown
  -i, --interactive       Select an occurrence, preview context, then show it
  -v, --verbose           Show full log paths and match positions on TTY
  --max-matches N         Maximum occurrences across sessions/hosts (default: 100, 0 = unlimited)
  --snippet-length N      Maximum Unicode characters per snippet (default: 240, minimum: 1)

One result per non-overlapping regex occurrence, not per session.
Sessions are ordered by modified_at descending; occurrences are in source order.
Default: session headings and compact passages with auto-pager on TTY;
plain TSV when piped. Paths and positions are hidden on TTY unless --verbose.
Verbose positions use "text #N" for search fragments, not transcript line numbers.
--verbose does not change JSON or TSV output.
TSV columns: path, agent, project, id, text_index, match_start, match_end, snippet, kind, position.
Text indices count nonempty source fragments before kind filtering (not transcript messages).
Use position with `ah show SESSION --at POSITION -C 2` to open the source.
Match offsets are 0-based UTF-8 byte offsets within the decoded search fragment.
Empty search fragments are skipped. No matches is successful with empty output.

Use PATTERN or -q, not both. Empty queries are rejected.
-p is shorthand for --kind user (all user text parts, excluding tool results).
-i uses fzf (or -s / $AH_SELECTOR); --no-preview disables the context preview.
-i cannot be combined with --json or --tsv. --raw-search is not supported;
use `ah log -q ... --raw-search` instead.
The former `search` alias for `log` is now this command; use `log` for session lists.

Examples:
  ah search 'OAuth'              # matching passages in the current directory
  ah search 'OAuth' -a --json    # occurrences across all directories
  ah search -p '認証'             # user prompts only

Global options:
  -a, --all               Show all sessions (disable default cwd filtering)
  -A                      Show all sessions including all configured remotes
  --agent <NAME>          Filter by agent name (e.g. claude, codex, gemini)
  --project <NAME>        Filter by project name
  -d, --dir <PATH>        Filter by working directory (default: current directory)
  -q, --query <REGEX>     Search messages and tool input/output (regex, case-insensitive)
  -p, --prompt-only       Search only user prompts (use with -q)
  --raw-search            Search raw session files incl. metadata (use with -q)
  -n, --limit N           Max session files to scan (default: 0, no limit)
  --since <SPEC>          Show sessions newer than (e.g. "2026-03-20", "3d", "1w", "2m" = ~60 days)
  --until <SPEC>          Show sessions older than (e.g. "2026-03-20", "3d", "1w", "2m" = ~60 days)
  --running               Show only currently running sessions (Claude, Codex, Copilot, Grok)
  --no-archived           Hide sessions the agent has archived (Codex)
  --subagents             Include subagent sessions (spawned by another session)
  --remote <NAME>         Include sessions from remote host (requires ah on remote; see ~/.ahrc [remotes.*])
  --color                 Force colored output (even through pipes)
  --no-color              Disable colored output
  --no-pager              Disable automatic pager
  --debug                 Show debug info (glob expansion, scan counts, timing) on stderr

ah show --help

Show session transcript

Usage:
  ah show [OPTIONS] [SESSION]

If SESSION is omitted, ah reads it from piped stdin (first line); if stdin is
a terminal or empty, ah shows the latest session matching -q and other filters.
Use - as SESSION to read it from stdin explicitly. An empty SESSION is an error.

Transcript output:
  --head N                Show first N messages only
  --at <POSITION>         Open a search position, including tool input/output
  -C, --context N         Surrounding source records with --at (default: 2, max: 1000)
  --pretty                Pretty-print with colors (default)
  --raw                   Output raw session file content
  --json                  Output normalized JSON Lines ({"role":"user","text":"..."})
  --md                    Output as Markdown (## User / ## Assistant headers)
  -f, --follow            Follow session output in real-time (like tail -f)
  --highlight <PATTERN>   Highlight matching text in pretty output (case-insensitive; requires color)

With --at, context counts nonempty searchable source records (a message or tool
event), not lines. Positions remain stable across kind filters and appends;
changed source prefixes require a new search. JSON emits record, fragment, kind,
text, selected, match_start, and match_end. --at conflicts with --head, --follow,
--raw, metadata output, and --highlight. Ordinary show output is unchanged.

Metadata output:
  -o, --fields <FIELDS>   Output session metadata as TSV instead of transcript
  --tsv                   Metadata mode without -o (default field: title)

Interactive mode:
  -i, --interactive       Select session via fuzzy finder then show it
  --interactive-display <FIELDS>  Override display columns in fuzzy finder
  -s <CMD>                Selector command (default: $AH_SELECTOR or fzf)
  --no-preview            Disable transcript preview
  ctrl-s (fzf only)       Toggle preview search: highlight + scroll to match / reset

Examples:
  ah show                            # show latest session transcript
  ah show -o title                    # output title of latest session
  ah show -o agent,title             # output agent and title as TSV
  ah show -i -o title                # select session, output title

Global options:
  -a, --all               Show all sessions (disable default cwd filtering)
  -A                      Show all sessions including all configured remotes
  --agent <NAME>          Filter by agent name (e.g. claude, codex, gemini)
  --project <NAME>        Filter by project name
  -d, --dir <PATH>        Filter by working directory (default: current directory)
  -q, --query <REGEX>     Search messages and tool input/output (regex, case-insensitive)
  -p, --prompt-only       Search only user prompts (use with -q)
  --raw-search            Search raw session files incl. metadata (use with -q)
  -n, --limit N           Max session files to scan (default: 0, no limit)
  --since <SPEC>          Show sessions newer than (e.g. "2026-03-20", "3d", "1w", "2m" = ~60 days)
  --until <SPEC>          Show sessions older than (e.g. "2026-03-20", "3d", "1w", "2m" = ~60 days)
  --running               Show only currently running sessions (Claude, Codex, Copilot, Grok)
  --no-archived           Hide sessions the agent has archived (Codex)
  --subagents             Include subagent sessions (spawned by another session)
  --remote <NAME>         Include sessions from remote host (requires ah on remote; see ~/.ahrc [remotes.*])
  --color                 Force colored output (even through pipes)
  --no-color              Disable colored output
  --no-pager              Disable automatic pager
  --debug                 Show debug info (glob expansion, scan counts, timing) on stderr

ah resume --help

Resume an agent session

Usage:
  ah resume [OPTIONS] [SESSION] [-- EXTRA_ARGS...]

If SESSION is omitted, ah reads it from piped stdin (first line); if stdin is
a terminal or empty, ah resumes the latest session matching -q and other filters.
Use - as SESSION to read it from stdin explicitly. An empty SESSION is an error.

Arguments after -- are passed directly to the agent command.

The only command that launches an agent process; other commands are read-only.

Options:
  --print                 Print the resolved resume command and exit (read-only; does not execute)

Interactive mode:
  -i, --interactive       Select session via fuzzy finder then resume it
  -o, --fields <FIELDS>   Display fields in interactive mode (default: agent,project,modified_at,title)
  -s <CMD>                Selector command (default: $AH_SELECTOR or fzf)
  --ltsv                  Use LTSV format for interactive selector display
  --no-preview            Disable transcript preview

Examples:
  ah resume                   # resume latest matching session
  ah resume --print           # print the resolved resume command
  ah resume a1b2c3d4          # resume by ID
  ah resume -i                # interactive selection
  ah resume -- --dry-run      # pass extra args to agent

Global options are also available (see ah -h).

ah project --help

List known projects

Usage:
  ah project [OPTIONS]

Options:
  -o, --fields <FIELDS>   Select output fields (replaces defaults, see --list-fields)
                          Default: project, session_count, last_modified_at, agents
                          In -i mode default: cwd, project, session_count, last_modified_at
  -O, --extra-fields <FIELDS>  Add fields to defaults (comma-separated)
  --table                 Aligned table with header row
  --tsv                   Tab-separated values (no header, no color)
  --ltsv                  Labeled Tab-Separated Values (in -i mode: selector display format)
  --json                  JSON Lines output
  -S, --sort <FIELD>      Sort by field (default: last_modified_at)
  --asc                   Sort ascending
  --desc                  Sort descending (default)
  -L, --list-fields       List available output fields and exit (use with --json for machine-readable output)

Default output (when no format flag is given):
  Aligned table with auto-pager on TTY, plain TSV when piped

Interactive mode:
  -i, --interactive       Browse projects via fuzzy finder; prints selected cwd
  -s <CMD>                Selector command (default: $AH_SELECTOR or fzf)
  --no-preview            Disable preview

Global options are also available (see ah -h).

ah memory --help

List agent memory files

Usage:
  ah memory [OPTIONS]

Options:
  -o, --fields <FIELDS>   Select output fields (replaces defaults, see --list-fields)
                          Default: agent, project, type, name, modified_at, description
  -O, --extra-fields <FIELDS>  Add fields to defaults (comma-separated)
  -t, --type <TYPE>       Filter by memory type (instruction/rule/memory/skill, or a memory's own type such as feedback)
  --table                 Aligned table with header row
  --tsv                   Tab-separated values (no header, no color)
  --ltsv                  Labeled Tab-Separated Values
  --json                  JSON Lines output
  -S, --sort <FIELD>      Sort by field (default: modified_at)
  --asc                   Sort ascending
  --desc                  Sort descending (default)
  -L, --list-fields       List available output fields and exit (use with --json for machine-readable output)

Default output (when no format flag is given):
  Aligned table with auto-pager on TTY, plain TSV when piped

A project-level AGENTS.md is listed as agent `shared` and matches any --agent filter.
Skills (SKILL.md) are listed only with -t skill.

Interactive mode:
  -i, --interactive       Browse memory files via fuzzy finder
  -s <CMD>                Selector command (default: $AH_SELECTOR or fzf)
  --no-preview            Disable preview

Global options are also available (see ah -h).

ah agent --help

Show session summary per agent

Usage:
  ah agent [OPTIONS]

Shows how many sessions were found for each agent and the latest modified time.

Options:
  --table                 Output as aligned table
  --tsv                   Output as TSV (tab-separated values)
  --ltsv                  Output as LTSV (Labeled TSV)
  --json                  Output as JSON Lines

Default output (when no format flag is given):
  Aligned table with auto-pager on TTY, plain TSV when piped

Global options are also available (see ah -h).

Configuration (~/.ahrc)

ah works out of the box with no configuration. Optionally, create ~/.ahrc (TOML) to customize agent settings and remote hosts.

File format

~/.ahrc has two top-level sections: [agents.*] for agent configuration and [remotes.*] for SSH remote hosts.

# ~/.ahrc — ah configuration file (TOML)

# --- Agent configuration ---

# Disable a built-in agent
[agents.codex]
disabled = true

# Add extra session file locations to a built-in agent
[agents.claude]
extra_patterns = ["~/claude-archive/projects/*/*.jsonl"]

# Define a custom agent using an existing plugin's parser
[agents.mybot]
plugin = "claude"
file_patterns = ["~/.mybot/sessions/*.jsonl"]

# --- Remote hosts for SSH session aggregation ---

[remotes.mydev]
host = "mydev"                     # SSH host name (as in ~/.ssh/config)
ah_path = "/usr/local/bin/ah"      # path to ah binary on remote (optional, default: "ah")

Agent fields

Field Required Description
disabled No Set to true to hide this agent from all commands
extra_patterns No Additional glob patterns to scan (built-in agents only)
plugin Yes* Parser to use: claude, codex, gemini, copilot, cursor, agy, grok, opencode (*required for custom agents)
file_patterns Yes* Glob patterns for session files (*required for custom agents)

All glob patterns must start with ~/ or / (absolute paths only). ~ is expanded to the home directory.

Disable an agent

[agents.codex]
disabled = true

Add extra file patterns to a built-in agent

[agents.claude]
extra_patterns = ["~/claude-archive/projects/*/*.jsonl"]

Sessions found through extra_patterns are attributed to the agent by the pattern's literal part (before the first glob character), so keep each agent's extra files in a dedicated directory or under a distinct name prefix. If the literal part cannot be told apart from your home directory or another agent's default directory (e.g. ~/*.jsonl, ~/.c*.db, ~/backup-*/x.db), ah warns and uses only the matches that fall inside the agent's own locations (e.g. ~/*/.claude/projects/*/*.jsonl still maps to Claude via its default .claude directory; with CLAUDE_CONFIG_DIR set, only paths under that directory do); other matches are skipped.

Add a custom agent (using an existing plugin's parser)

[agents.mybot]
plugin = "claude"
file_patterns = ["~/.mybot/sessions/*.jsonl"]

The plugin field tells ah how to parse the session files. Available plugins: claude, codex, gemini, copilot, cursor, agy, grok, opencode.

Remote hosts

Aggregate sessions from remote machines over SSH. The remote host must have ah installed.

[remotes.mydev]
host = "mydev"                       # SSH host (must be reachable via `ssh <host>`)
ah_path = "/usr/local/bin/ah"        # optional, default: "ah"

[remotes.prod-bastion]
host = "bastion.example.com"
Field Required Description
host Yes SSH host name (as configured in ~/.ssh/config or a hostname)
ah_path No Absolute path to ah on the remote host or a bare command name (default: "ah"). ~/bin/ah and other ~/... paths are not supported

Use --remote <name> to include a specific remote, or -A to include all configured remotes:

ah log --remote mydev              # include sessions from mydev
ah log -A                          # include all configured remotes
ah log -A -q "deploy"              # search across local + all remotes

Environment variables

Each built-in agent respects the environment variable its CLI uses to relocate session storage:

Agent Session Files Env Var Default
Claude projects/*/*.jsonl CLAUDE_CONFIG_DIR ~/.claude
Codex sessions/**/*.jsonl CODEX_HOME ~/.codex
Gemini tmp/*/chats/session-*.jsonl (.json before v0.39) GEMINI_CLI_HOME ~/.gemini
Copilot session-state/*/workspace.yaml COPILOT_HOME ~/.copilot
Cursor projects/*/agent-transcripts/**/*.jsonl CURSOR_DATA_DIR ~/.cursor
Antigravity (agy) antigravity-cli/brain/*/.system_generated/logs/transcript.jsonl — ~/.gemini
Grok sessions/*/*/chat_history.jsonl GROK_HOME ~/.grok
opencode opencode/opencode*.db (SQLite) XDG_DATA_HOME ~/.local/share

opencode stores all sessions in one SQLite database. ah reads it read-only and lists each session under the virtual path <db>/<session-id>, which works with ah show, ah resume, and -o path like a regular session file. ah show --raw prints one JSON line per message with its parts.

Codex sessions archived with codex archive stay listed and resumable (codex resume still finds them). They carry archived=true (-o archived); hide them with --no-archived.

Subagent sessions (started by another session, e.g. Claude's Task tool) are hidden from log, project, and agent unless --subagents is given; -o parent_id shows the session that spawned them. A subagent's id or path still works with ah show directly. Claude, Cursor, and Gemini subagent transcripts cannot be resumed on their own, so they have no resume command.

Agent Subagent sessions parent_id
Claude projects/*/<parent>/subagents/agent-<id>.jsonl (id is the agent id) ✓
Codex sessions whose session_meta source is a subagent ✓ (spawned threads)
Gemini tmp/*/chats/<parent>/<id>.json(l) ✓
Cursor projects/*/agent-transcripts/<parent>/subagents/*.jsonl ✓
Grok summary.json with session_kind: subagent not recorded
opencode child sessions (parent_id column) ✓

Run ah list-agents to see the full configuration including glob patterns and capabilities.

Additional environment variables:

Env Var Description
AH_PAGER Override pager command (default: less). Set to empty string to disable
PAGER Fallback pager command (used if AH_PAGER is not set)
AH_COLOR Set to 1 to force colored output (like --color)
NO_COLOR Set to disable colored output (no-color.org)

Examples

SQL with trdsql

ah log -a --ltsv | trdsql -iltsv "SELECT * FROM - WHERE agent='claude'"
ah log -a --ltsv | trdsql -iltsv "SELECT agent, COUNT(*) as cnt FROM - GROUP BY agent"

JSON with jq

ah log -a --json | jq '.project'
ah log -a --json -n 1 | jq '.'
ah project --json | jq '.project'       # list project names

Piping

ah log -q "auth" -o path | head -1 | ah show    # show latest match
ah log -q "auth" -o path | head -1 | ah resume  # resume latest match
ah log -a -o project | sort | uniq -c | sort -rn # project ranking

For AI Agents (CLAUDE.md / AGENTS.md)

Add this line to your project or global instructions so your coding agent knows about ah:

`ah` — cross-agent session history CLI. Run `ah -h` for usage; key commands: `ah log` (list sessions), `ah show` (view transcript), `ah log -a -q "keyword"` (search all).

License

MIT

About

Agent History — search and browse AI coding agent sessions (Claude, Codex, Gemini, Copilot, Cursor) from a single CLI

Topics

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages