feat: update install CLI, ESM compat, and Gemini CLI docs

Fixes CursorHooksInstaller ESM compatibility, updates install command
with improved path resolution, and refreshes built plugin artifacts.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Alex Newman
2026-04-03 12:38:45 -07:00
parent 5621b67ccd
commit 76a880a3d6
11 changed files with 423 additions and 204 deletions
+8 -1
View File
@@ -133,6 +133,12 @@ Install with a single command:
npx claude-mem install
```
Or install for Gemini CLI (auto-detects `~/.gemini`):
```bash
npx claude-mem install --ide gemini-cli
```
Or install from the plugin marketplace inside Claude Code:
```
@@ -141,7 +147,7 @@ Or install from the plugin marketplace inside Claude Code:
/plugin install claude-mem
```
Restart Claude Code. Context from previous sessions will automatically appear in new sessions.
Restart Claude Code or Gemini CLI. Context from previous sessions will automatically appear in new sessions.
> **Note:** Claude-Mem is also published on npm, but `npm install -g claude-mem` installs the **SDK/library only** — it does not register the plugin hooks or set up the worker service. Always install via `npx claude-mem install` or the `/plugin` commands above.
@@ -177,6 +183,7 @@ The installer handles dependencies, plugin setup, AI provider configuration, wor
### Getting Started
- **[Installation Guide](https://docs.claude-mem.ai/installation)** - Quick start & advanced installation
- **[Gemini CLI Setup](https://docs.claude-mem.ai/gemini-cli/setup)** - Dedicated guide for Google's Gemini CLI integration
- **[Usage Guide](https://docs.claude-mem.ai/usage/getting-started)** - How Claude-Mem works automatically
- **[Search Tools](https://docs.claude-mem.ai/usage/search-tools)** - Query your project history with natural language
- **[Beta Features](https://docs.claude-mem.ai/beta-features)** - Try experimental features like Endless Mode
+7
View File
@@ -57,6 +57,13 @@
"cursor/openrouter-setup"
]
},
{
"group": "Gemini CLI Integration",
"icon": "terminal",
"pages": [
"gemini-cli/setup"
]
},
{
"group": "Best Practices",
"icon": "lightbulb",
+192
View File
@@ -0,0 +1,192 @@
---
title: "Gemini CLI Setup"
description: "Add persistent memory to Gemini CLI with claude-mem"
---
# Gemini CLI Setup
> **Give Gemini CLI persistent memory across sessions.**
Gemini CLI starts every session from scratch. Claude-mem changes that by capturing observations, decisions, and patterns — then injecting relevant context into each new session.
<Info>
**How it works:** Claude-mem installs lifecycle hooks into Gemini CLI that capture tool usage, agent responses, and session events. A local worker service extracts semantic observations and injects relevant history at session start.
</Info>
## Prerequisites
- [Gemini CLI](https://github.com/google-gemini/gemini-cli) installed and configured
- [Node.js](https://nodejs.org/) 18+
- The `~/.gemini` directory must exist (created by Gemini CLI on first run)
## Installation
### Step 1: Install claude-mem
```bash
npx claude-mem install
```
The installer will:
1. Auto-detect Gemini CLI (checks for `~/.gemini` directory)
2. Prompt you to select **Gemini CLI** from the IDE picker
3. Install 8 lifecycle hooks into `~/.gemini/settings.json`
4. Inject context configuration into `~/.gemini/GEMINI.md`
5. Start the worker service
### Step 2: Configure an AI provider
Claude-mem needs an AI provider to extract observations from your sessions. Choose one:
<Tabs>
<Tab title="Gemini API (Free)">
The simplest option — use Gemini's own API for observation extraction:
1. Get a free API key from [Google AI Studio](https://aistudio.google.com/apikey)
2. Add it to your settings:
```bash
mkdir -p ~/.claude-mem
cat > ~/.claude-mem/settings.json << 'EOF'
{
"CLAUDE_MEM_PROVIDER": "gemini",
"CLAUDE_MEM_GEMINI_API_KEY": "YOUR_API_KEY"
}
EOF
```
<Tip>
**Free tier:** 1,500 requests/day with `gemini-2.5-flash-lite`. Enable billing on Google Cloud for 4,000 RPM without charges.
</Tip>
</Tab>
<Tab title="Claude SDK">
If you have a Claude API key:
```bash
mkdir -p ~/.claude-mem
cat > ~/.claude-mem/settings.json << 'EOF'
{
"CLAUDE_MEM_PROVIDER": "claude"
}
EOF
```
Set your API key via environment variable:
```bash
export ANTHROPIC_API_KEY="your-key"
```
</Tab>
<Tab title="OpenRouter">
For access to 100+ models:
```bash
mkdir -p ~/.claude-mem
cat > ~/.claude-mem/settings.json << 'EOF'
{
"CLAUDE_MEM_PROVIDER": "openrouter",
"CLAUDE_MEM_OPENROUTER_API_KEY": "YOUR_KEY"
}
EOF
```
</Tab>
</Tabs>
### Step 3: Verify installation
```bash
# Check worker is running
npx claude-mem status
# Check hooks are installed — look for claude-mem entries
cat ~/.gemini/settings.json | grep claude-mem
```
Open http://localhost:37777 to see the memory viewer.
### Step 4: Start using Gemini CLI
Launch Gemini CLI normally. Claude-mem works in the background:
```bash
gemini
```
On session start, you'll see claude-mem context injected with your recent observations and project history.
## What gets captured
Claude-mem registers 8 of Gemini CLI's 11 lifecycle hooks:
| Hook | Purpose |
|------|---------|
| **SessionStart** | Injects memory context into the session |
| **SessionEnd** | Marks session complete, triggers summary |
| **PreCompress** | Captures session summary before compression |
| **Notification** | Records system events (permissions, etc.) |
| **BeforeAgent** | Captures user prompts |
| **AfterAgent** | Records full agent responses |
| **BeforeTool** | Logs tool invocations before execution |
| **AfterTool** | Captures tool results after execution |
Three model-level hooks (BeforeModel, AfterModel, BeforeToolSelection) are intentionally skipped — they fire per-LLM-call and are too noisy for memory capture.
## Troubleshooting
### Hooks not firing
1. Verify hooks exist in settings:
```bash
cat ~/.gemini/settings.json
```
You should see entries like `"SessionStart"`, `"AfterTool"`, etc. with claude-mem commands.
2. Restart Gemini CLI after installation.
3. Re-run the installer:
```bash
npx claude-mem install
```
### Worker not running
```bash
# Check status
npx claude-mem status
# View logs
npx claude-mem logs
# Restart worker
npx claude-mem restart
```
### No context appearing at session start
1. Ensure the worker is running (check http://localhost:37777)
2. You need at least one previous session with observations for context to appear
3. Check your AI provider is configured in `~/.claude-mem/settings.json`
### Raw escape codes in output
If you see characters like `[31m` or `[0m` in the session context, your claude-mem version may need updating:
```bash
npx claude-mem install
```
This was fixed in v10.6.3+ — the Gemini CLI adapter now strips ANSI color codes automatically.
## Uninstalling
```bash
npx claude-mem uninstall
```
This removes hooks from `~/.gemini/settings.json` and cleans up `~/.gemini/GEMINI.md`.
## Next Steps
- [Gemini Provider](/usage/gemini-provider) — Configure the Gemini AI provider for observation extraction
- [Configuration](/configuration) — All settings options
- [Search Tools](/usage/search-tools) — Search your memory from within sessions
- [Troubleshooting](/troubleshooting) — Common issues and solutions
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+2 -1
View File
@@ -109,7 +109,8 @@ export const geminiCliAdapter: PlatformAdapter = {
}
if (result.systemMessage) {
output.systemMessage = result.systemMessage;
// Strip ANSI escape codes — Gemini CLI renders them as raw text
output.systemMessage = result.systemMessage.replace(/\x1b\[[0-9;]*m/g, '');
}
// hookSpecificOutput is a first-class Gemini CLI field — pass through directly
+1 -1
View File
@@ -39,7 +39,7 @@ export const contextHandler: EventHandler = {
// Pass all projects (parent + worktree if applicable) for unified timeline
const projectsParam = context.allProjects.join(',');
const apiPath = `/api/context/inject?projects=${encodeURIComponent(projectsParam)}`;
const colorApiPath = `${apiPath}&colors=true`;
const colorApiPath = input.platform === 'claude-code' ? `${apiPath}&colors=true` : apiPath;
// Note: Removed AbortSignal.timeout due to Windows Bun cleanup issue (libuv assertion)
// Worker service has its own timeouts, so client-side timeout is redundant
+3 -1
View File
@@ -23,9 +23,11 @@ export const userMessageHandler: EventHandler = {
const project = basename(input.cwd ?? process.cwd());
// Fetch formatted context directly from worker API
// Only request ANSI colors for platforms that render them (claude-code)
const colorsParam = input.platform === 'claude-code' ? '&colors=true' : '';
try {
const response = await workerHttpRequest(
`/api/context/inject?project=${encodeURIComponent(project)}&colors=true`
`/api/context/inject?project=${encodeURIComponent(project)}${colorsParam}`
);
if (!response.ok) {
+27 -13
View File
@@ -230,22 +230,36 @@ async function promptForIDESelection(): Promise<string[]> {
function copyPluginToMarketplace(): void {
const marketplaceDir = marketplaceDirectory();
const packageRoot = npmPackageRootDirectory();
ensureDirectoryExists(marketplaceDir);
// Copy the entire npm package (not just plugin/) so that package.json,
// node_modules, and scripts are all present in the marketplace dir.
const packageRoot = npmPackageRootDirectory();
cpSync(packageRoot, marketplaceDir, {
recursive: true,
force: true,
filter: (source) => {
// Skip .git and other unnecessary directories
if (source.includes('.git') && !source.includes('.claude-plugin')) return false;
if (source.endsWith('.tgz')) return false;
return true;
},
});
// Only copy directories/files that are actually needed at runtime.
// The npm package ships plugin/, package.json, node_modules/, openclaw/, dist/.
// When running from a dev checkout, the root contains many extra dirs
// (.claude, .agents, src, docs, etc.) that must NOT be copied.
const allowedTopLevelEntries = [
'plugin',
'package.json',
'package-lock.json',
'node_modules',
'openclaw',
'dist',
'LICENSE',
'README.md',
'CHANGELOG.md',
];
for (const entry of allowedTopLevelEntries) {
const sourcePath = join(packageRoot, entry);
const destPath = join(marketplaceDir, entry);
if (!existsSync(sourcePath)) continue;
cpSync(sourcePath, destPath, {
recursive: true,
force: true,
});
}
}
function copyPluginToCache(version: string): void {
@@ -133,9 +133,7 @@ export function findMcpServerPath(): string | null {
const possiblePaths = [
// Marketplace install location
path.join(MARKETPLACE_ROOT, 'plugin', 'scripts', 'mcp-server.cjs'),
// Development/source location (relative to built worker-service.cjs in plugin/scripts/)
path.join(path.dirname(__filename), 'mcp-server.cjs'),
// Alternative dev location
// Development/source location
path.join(process.cwd(), 'plugin', 'scripts', 'mcp-server.cjs'),
];
@@ -155,9 +153,7 @@ export function findWorkerServicePath(): string | null {
const possiblePaths = [
// Marketplace install location
path.join(MARKETPLACE_ROOT, 'plugin', 'scripts', 'worker-service.cjs'),
// Development/source location (relative to built worker-service.cjs in plugin/scripts/)
path.join(path.dirname(__filename), 'worker-service.cjs'),
// Alternative dev location
// Development/source location
path.join(process.cwd(), 'plugin', 'scripts', 'worker-service.cjs'),
];