Gemini CLI¶
Gemini CLI keeps a prompt-history log alongside active JSONL and legacy JSON
chat files. Normal search reads the prompt log; --exhaustive also projects prompts
from the chat files. The prompt-log adapter has no proof-bound targeted route,
so --deep does not select Gemini conversations.
Base path: ~/.gemini (env override: GEMINI_CLI_HOME).
observed_version: gemini-cli v0.54.4 (observed 2026-08-08);
types pinned at HEAD 927170fc.
Stores¶
- Role:
app_state- Format:
json_object- Coverage:
catalog_only- Adapter:
-
- Role:
source_tree- Format:
opaque- Coverage:
catalog_only- Adapter:
-
- Role:
source_tree- Format:
opaque- Coverage:
catalog_only- Adapter:
-
- Role:
primary_chat- Format:
jsonl- Coverage:
default_search- Adapter:
gemini.tmp_chats_jsonl.v1
- Role:
supplementary_chat- Format:
json_object- Coverage:
catalog_only- Adapter:
-
- Role:
prompt_history- Format:
json_array- Coverage:
default_search- Adapter:
gemini.tmp_logs_json.v1
- Role:
supplementary_chat- Format:
json_object- Coverage:
default_search- Adapter:
gemini.tmp_chats_legacy_json.v1
- Role:
app_state- Format:
md_frontmatter- Coverage:
catalog_only- Adapter:
-
- Role:
app_state- Format:
json_object- Coverage:
catalog_only- Adapter:
-
- Role:
persistent_memory- Format:
text- Coverage:
inspectable- Adapter:
gemini.memory_text.v1
- Role:
app_state- Format:
text- Coverage:
inspectable- Adapter:
gemini.tool_outputs_text.v1
gemini.projects_registry¶
{"projects": {<absolute_project_root>: <directory_name>}} — the registry mapping each project to the directory Gemini chose for it under both tmp/ and history/. It is the only lookup that covers every naming scheme: gemini_project_hash reproduces the sha256 scheme alone, and most directories are now basename slugs or run stamps. No prompt text, but the reverse index a project-scoped query wants.
- Agent:
Gemini
- Role:
app_state- Format:
json_object- Coverage:
catalog_only- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/projects.json- Adapter:
-
- Data version:
-- Version strategies:
shape_inference- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
no
gemini.history¶
Checkpointing shadow-git root, one directory per project holding a .project_root marker and, where checkpointing has run, a full .git/. File snapshots for restore, not conversation: despite the name it is not an archive of expired sessions, which sessionCleanup.ts hard-deletes. Catalogued so the name does not mislead a future adapter into reading it as prompt history.
- Agent:
Gemini
- Role:
source_tree- Format:
opaque- Coverage:
catalog_only- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/history/<project>/- Adapter:
-
- Data version:
-- Version strategies:
catalog_observation- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
no
gemini.worktrees¶
Git worktrees created by -w/--worktree behind the experimental.worktrees setting, checked out inside the repository on a branch named worktree-<name> — the same convention as claude.worktrees. No index file; a worktree gets its own hashed tmp/ directory with no pointer back, so projects.json is the only mapping. Catalogued so the adapter never indexes a working tree as chat.
- Agent:
Gemini
- Role:
source_tree- Format:
opaque- Coverage:
catalog_only- Path:
<project_root>/.gemini/worktrees/<name>- Adapter:
-
- Data version:
-- Version strategies:
catalog_observation- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
no
gemini.tmp.chats¶
JSONL with mixed record types. Line 1 is a SessionMetadataRecord (sessionId, projectHash, startTime, lastUpdated, kind). Subsequent lines are MessageRecord turns (id, timestamp, type, content, optional toolCalls/thoughts/tokens/model/displayContent) interleaved with MetadataUpdateRecord updates ({$set: ...}). content is the searched (expanded) form; the occasional displayContent key is the UI-echo variant. Upstream types also declare RewindRecord and PartialMetadataRecord plus type values info/error/warning. The CLI does write info/error system records, but agentgrep surfaces only the user and gemini conversation turns and skips the system records. Adapter store field uses the underscore-flattened form gemini.tmp_chats.
- Agent:
Gemini
- Role:
primary_chat- Format:
jsonl- Coverage:
default_search- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/tmp/<project_hash>/chats/session-<timestamp><id>.jsonl- Adapter:
gemini.tmp_chats_jsonl.v1- Data version:
-- Version strategies:
-- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
yes
Record keys by type observed (0.54.4, 2026-08-08)
- Keys:
$rewindTo,$set,kind,lastUpdated,projectHash,sessionId,startTime- gemini:
content,id,model,thoughts,timestamp,tokens,toolCalls,type- info:
content,id,timestamp,type- user:
content,displayContent,id,timestamp,type
Parsed by agentgrep via parse_gemini_chat_file (gemini.tmp_chats_jsonl.v1). When a gemini-typed record’s content is empty, the assistant’s prose is drawn from thoughts[*].subject/description and the tool-call context from toolCalls[*].name/description — concatenated into one SearchRecord per turn.
gemini.tmp.checkpoints¶
Single-file conversation snapshot written by the /chat save command. JSON object { history: Content[]; authType?: AuthType } where each Content is {role: 'user'|'model', parts: [...]}.
- Agent:
Gemini
- Role:
supplementary_chat- Format:
json_object- Coverage:
catalog_only- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/tmp/<project_hash>/chats/checkpoint-<tag>.json- Adapter:
-
- Data version:
-- Version strategies:
-- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
no
User-named snapshots vs. continuous transcript.
gemini.tmp.logs¶
JSON array of LogEntry { sessionId, messageId, timestamp, type, message } — user-prompt audit log. Adapter store field uses the underscore-flattened form gemini.tmp_logs.
- Agent:
Gemini
- Role:
prompt_history- Format:
json_array- Coverage:
default_search- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/tmp/<project_hash>/logs.json- Adapter:
gemini.tmp_logs_json.v1- Data version:
-- Version strategies:
-- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
yes
Record keys by type observed (0.54.4, 2026-08-08)
- user:
message,messageId,sessionId,timestamp,type
Parsed by agentgrep via parse_gemini_logs_file (gemini.tmp_logs_json.v1).
gemini.tmp.chats_legacy¶
Pre-Feb 2026 single-file session format. JSON object with top-level sessionId, projectHash, startTime, lastUpdated, and a messages array carrying the same per-turn fields as the current JSONL format. Upstream still reads this shape via the isLegacyRecord discriminator. Adapter store field uses the underscore-flattened form gemini.tmp_chats_legacy.
- Agent:
Gemini
- Role:
supplementary_chat- Format:
json_object- Coverage:
default_search- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/tmp/<project_hash>/chats/session-<timestamp><id>.json- Adapter:
gemini.tmp_chats_legacy_json.v1- Data version:
-- Version strategies:
-- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
yes
Record keys by kind observed (0.54.4, 2026-08-08)
- main:
kind,lastUpdated,messages,projectHash,sessionId,startTime
Parsed by agentgrep via parse_gemini_chat_legacy_file (gemini.tmp_chats_legacy_json.v1). Covers sessions whose files predate the JSONL migration; upstream still handles them.
gemini.skills¶
gemini.settings¶
gemini.memory¶
Global user-authored context/memory Markdown injected into Gemini CLI sessions — the Gemini analogue of Claude’s CLAUDE.md. Standing instructions, not chat; inspectable opt-in rather than searched by default.
- Agent:
Gemini
- Role:
persistent_memory- Format:
text- Coverage:
inspectable- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/GEMINI.md- Adapter:
gemini.memory_text.v1- Data version:
gemini.memory.markdown.v1- Version strategies:
shape_inference, catalog_observation- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
no
gemini.tool_outputs¶
Per-tool-call output text (run_shell_command / read_file / update_topic results) under tmp/<hash>/tool-outputs/session-<id>/. Tool output rather than user prompts (may echo file or command content), so inspectable opt-in, not searched by default.
- Agent:
Gemini
- Role:
app_state- Format:
text- Coverage:
inspectable- Path:
${GEMINI_CLI_HOME or ${HOME}/.gemini}/tmp/<project_hash>/tool-outputs/session-<id>/<name>.txt- Adapter:
gemini.tool_outputs_text.v1- Data version:
-- Version strategies:
-- Observed:
gemini-cli v0.54.4 (2026-08-08)
- Default search:
no
Record schemas¶
Active chat JSONL¶
gemini.tmp.chats is JSONL with mixed record types. Line 1 is a
SessionMetadataRecord (sessionId, projectHash, startTime,
lastUpdated, kind). Subsequent lines are MessageRecord turns (id,
timestamp, type, content) interleaved with MetadataUpdateRecord updates
({$set: {...}}). Some user records also carry displayContent (the UI-echo
variant); content is the expanded form agentgrep searches.
For gemini-typed records whose content is empty, the assistant’s
prose is drawn from thoughts[*].subject/description and the
tool-call context from toolCalls[*].name/description.
Legacy chat JSON¶
gemini.tmp.chats_legacy is the pre-Feb 2026 single-file .json
format. It is a JSON object with session metadata at the top level and the full
conversation under a messages array.
Prompt logs¶
gemini.tmp.logs is a flat JSON array of
LogEntry { sessionId, messageId, timestamp, type, message } — a user-prompt
audit log.
Memory file¶
gemini.memory is ~/.gemini/GEMINI.md — the global user-authored
context/memory file injected into Gemini CLI sessions, the analogue of
Claude’s CLAUDE.md. Standing instructions rather than chat, so it is
inspectable (opt-in) rather than searched by default.
How a project directory is named¶
Gemini has named tmp/ project directories three different ways over
time, and a long-lived home holds all three at once. One tree here
carries 38 SHA-256 directories, 59 run-scoped names shaped like
20260424-214247z-3714694-63ea, and 45 plain project-basename slugs.
You do not have to care for search: agentgrep walks tmp/ recursively,
so every scheme is found. You do have to care for two narrower things.
gemini_project_hash() reproduces the
SHA-256 scheme only. It still answers “which directory holds this
repo?” for a hash-named tree, and answers nothing for the other two —
so treat it as a reader for older layouts, not as a general lookup.
The reverse index that does cover every scheme is projects.json,
which maps each absolute project root to the directory name Gemini
chose for it.
A cwd_hash is published only when the directory name really is a
digest. A basename slug is not one, and labelling it as such would
answer cwd_hash: with a value no agent ever wrote, so agentgrep
leaves the field unset instead — see How agentgrep learns a working directory. The
literal working directory is unaffected; it comes from the sibling
.project_root file either way.
Project context¶
Store |
|
|
|
|---|---|---|---|
assistant turn’s |
metadata line’s |
— |
|
— |
sibling |
— |
|
— |
sibling |
— |
All three prompt stores live under one tmp/<project>/ directory, and
the literal path is on disk in two places: the session metadata line
names it in a plural directories array — where every other agent
writes a scalar cwd — and Gemini drops a .project_root file beside
the directory. agentgrep reads both, so Gemini records answer --cwd,
cwd:, repo:, and project:. Both sources are
lossless; a missing .project_root is
ordinary on older trees and simply leaves the record without a cwd.
cwd_hash is the narrower field. A record carries one only when its
project directory is genuinely a digest, so a hash-named tree answers
cwd_hash: and a slug-named tree does not. Filtering by cwd: reaches
both, which is why it is the better habit for this backend.
Gemini records no git branch in any of its prompt stores, so branch:
does not reach this backend.