-
Notifications
You must be signed in to change notification settings - Fork 0
Implement Gemini CLI session importer with ProjectRegistry support for future versions #1
Description
Gemini CLI Adapter Implementation Guide
Overview
This document describes the implementation of the Gemini CLI session adapter for my-mega-memory. It covers the current structure, the project hash problem, and how to implement the future solution when the ProjectRegistry feature becomes available.
Current Gemini CLI Structure
Session File Location
~/.gemini/tmp/{projectHash}/chats/session-{timestamp}-{id}.json
Example:
~/.gemini/tmp/78e0c7326cf29ebec3d3e54ec35141c0af295bdb67fc76f00e79dc9cff73ba00/chats/session-2026-02-08T17-31-26d30166.json
Session File Format
{
"sessionId": "26d30166-6e7c-4881-bd90-233138784e9d",
"projectHash": "78e0c7326cf29ebec3d3e54ec35141c0af295bdb67fc76f00e79dc9cff73ba00",
"startTime": "2026-02-08T17:31:42.123Z",
"lastUpdated": "2026-02-08T17:31:42.123Z",
"messages": [
{
"id": "dd659bea-ce51-4962-892d-db3487116dcf",
"timestamp": "2026-02-08T17:31:42.123Z",
"type": "user|gemini|error",
"content": "message content",
"thoughts": [
{
"subject": "thought subject",
"description": "thought description",
"timestamp": "2026-02-08T17:31:42.123Z"
}
],
"tokens": {
"input": 100,
"output": 50,
"cached": 0,
"thoughts": 10,
"tool": 0,
"total": 160
},
"model": "gemini-3-pro-preview"
}
]
}Message Types
user- User messagesgemini- Assistant responses (may includethoughtsarray)error- Error messages
The Project Hash Problem
How the Hash is Generated
The projectHash is a SHA256 hash of the absolute project path:
// From: external/gemini-cli/packages/core/src/utils/paths.ts:325
export function getProjectHash(projectRoot: string): string {
return crypto.createHash('sha256').update(projectRoot).digest('hex');
}Example:
Path: /home/daniel/projects/my-mega-memory
Hash: 78e0c7326cf29ebec3d3e54ec35141c0af295bdb67fc76f00e79dc9cff73ba00
Why the Hash Cannot Be Reversed
SHA256 is a one-way cryptographic hash function. It is mathematically impossible to reverse the hash back to the original path.
Current Status (Version 0.27.3)
As of Gemini CLI v0.27.3 (commit d5a135b14), there is no mapping file that associates hashes with project names.
Current Solution: Use the hash (first 8 characters) as the project name:
Project name: gemini-78e0c73
Project path: gemini-78e0c73 (same, since no real path is known)
Future Solution: ProjectRegistry Feature
Feature Availability
The ProjectRegistry feature was introduced in commit 6fb3b0900 ("Shorten temp directory #17901"), which is 172 commits after v0.27.3. This feature will be available in v0.28.x or later nightly builds.
What Changes
When the ProjectRegistry feature is active, Gemini CLI creates:
~/.gemini/projects.json- Maps project paths to short identifiers (slugs)~/.gemini/history/- New directory structure with slug-based organization- Slug-based temp directories -
~/.gemini/tmp/{slug}/instead of hash-based
projects.json Structure
{
"projects": {
"/home/daniel/projects/my-mega-memory": "my-mega-memory",
"/home/daniel/projects/other-project": "other-project-1",
"/home/daniel/projects/my-project-2": "my-project-2"
}
}How to Reverse-Lookup a Hash
Since the projects.json contains path -> slug mappings, we need to compute the hash for each path to find a match:
import * as crypto from 'crypto';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
interface ProjectsJson {
projects: Record<string, string>;
}
function computeProjectHash(projectPath: string): string {
return crypto.createHash('sha256').update(projectPath).digest('hex');
}
/**
* Find project name by hash using projects.json
* @returns { projectPath, slug } or null if not found
*/
function findProjectByHash(projectHash: string): { projectPath: string; slug: string } | null {
const projectsJsonPath = path.join(os.homedir(), '.gemini', 'projects.json');
if (!fs.existsSync(projectsJsonPath)) {
return null; // Feature not active yet
}
try {
const content = fs.readFileSync(projectsJsonPath, 'utf-8');
const data = JSON.parse(content) as ProjectsJson;
for (const [projectPath, slug] of Object.entries(data.projects)) {
const hash = computeProjectHash(projectPath);
if (hash === projectHash) {
return { projectPath, slug };
}
}
return null; // Hash not found in registry
} catch (e) {
console.error('Error reading projects.json:', e);
return null;
}
}Implementation Instructions
Step 1: Check if projects.json Exists
Before trying to resolve hashes, check if the ProjectRegistry feature is active:
const PROJECTS_JSON_PATH = path.join(os.homedir(), '.gemini', 'projects.json');
function isProjectRegistryActive(): boolean {
return fs.existsSync(PROJECTS_JSON_PATH);
}Step 2: Update GeminiSessionFinder
Modify src/adapters/gemini/index.ts to resolve project names:
export class GeminiSessionFinder {
// ... existing code ...
private resolveProjectName(projectHash: string): string {
// Try to resolve using projects.json if available
const resolved = this.findProjectByHash(projectHash);
if (resolved) {
return resolved.slug; // or resolved.projectPath for full path
}
// Fallback: use hash as project name
return `gemini-${projectHash.slice(0, 8)}`;
}
private findProjectByHash(projectHash: string): { projectPath: string; slug: string } | null {
// Implementation from above
// ... (insert findProjectByHash code here)
}
}Step 3: Update listSessions Method
When listing sessions, use the resolved project name:
listSessions(): GeminiSessionInfo[] {
const sessions: GeminiSessionInfo[] = [];
// ... existing code ...
for (const projectHash of projectDirs) {
const projectName = this.resolveProjectName(projectHash);
const projectPath = this.resolveProjectPath(projectHash); // if needed
// ... rest of implementation ...
}
return sessions;
}Step 4: Handle Migration Scenarios
When users upgrade from v0.27.3 to a version with ProjectRegistry:
- Old sessions still use hash-based directories
- New sessions use slug-based directories
- The adapter should handle both:
private listSessionDirectories(): string[] {
const tmpDir = path.join(os.homedir(), '.gemini', 'tmp');
// List all subdirectories (both hash and slug based)
if (!fs.existsSync(tmpDir)) {
return [];
}
return fs.readdirSync(tmpDir, { withFileTypes: true })
.filter(dirent => dirent.isDirectory())
.map(dirent => dirent.name);
}
private isHashDirectory(name: string): boolean {
// Hash directories are 64 hex characters
return /^[a-f0-9]{64}$/.test(name);
}
private resolveProjectDirectory(dirName: string): { hash?: string; slug?: string } {
if (this.isHashDirectory(dirName)) {
return { hash: dirName };
}
return { slug: dirName };
}Step 5: Update GeminiAdapter
Modify src/adapters/gemini/adapter.ts to use resolved project names:
async getSessions(): Promise<SessionWithProject[]> {
const sessions: SessionWithProject[] = [];
const sessionInfos = this.finder.listSessions();
for (const info of sessionInfos) {
// projectName and projectPath are now resolved by the finder
const projectName = info.projectName; // e.g., "my-mega-memory" or "gemini-78e0c73"
const projectPath = info.projectPath; // e.g., "/home/daniel/projects/my-mega-memory" or fallback
sessions.push({
session,
provider: SessionProvider.GEMINI,
projectPath,
projectName,
title: session.title,
created: toDateTimeString(info.created),
updated: toDateTimeString(info.updated),
});
}
return sessions;
}Testing
Test Case 1: No projects.json (v0.27.3)
// Should fall back to hash-based names
expect(projectName).toBe('gemini-78e0c73');Test Case 2: With projects.json (v0.28.x+)
// Should use resolved slug from registry
expect(projectName).toBe('my-mega-memory');Test Case 3: Hash not in registry
// Should fall back to hash-based name
expect(projectName).toBe('gemini-01ae9d04');Migration Strategy
When users upgrade to v0.28.x+, the adapter will automatically:
- Detect if
projects.jsonexists - Use it for hash resolution when available
- Fall back to hash-based names for unmapped projects
- Handle both hash-based and slug-based directories
No manual migration is required for the adapter.
References
- Gemini CLI Source:
external/gemini-cli/ - ProjectRegistry:
external/gemini-cli/packages/core/src/config/projectRegistry.ts - Storage (hash generation):
external/gemini-cli/packages/core/src/config/storage.ts - Paths utilities:
external/gemini-cli/packages/core/src/utils/paths.ts
Version Information
| Component | Version | Commit | Status |
|---|---|---|---|
| Current User Version | v0.27.3 | d5a135b14 | No ProjectRegistry |
| ProjectRegistry Feature | v0.28.x+ | 6fb3b0900 | Includes projects.json |
The ProjectRegistry feature was introduced 172 commits after v0.27.3.