Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [0.3.0] - 2026-02-12
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changelog introduces a 0.3.0 release entry, but package.json is currently version 0.2.1. Either bump the package version as part of this release documentation, or adjust the changelog entry/versioning so the repository stays consistent.

Suggested change
## [0.3.0] - 2026-02-12
## [Unreleased]

Copilot uses AI. Check for mistakes.

### Added

- **Claude Code hooks integration** — three lifecycle hooks that give Claude persistent project memory:
- `session-start` — loads stored memories into Claude's context at session start
- `session-stop` — captures new memories from commits made during the session
- `prompt-submit` — surfaces relevant memories per prompt (disabled by default)
- **`git-mem init-hooks`** command — one-command setup for Claude Code hooks:
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command name should be git-mem init not git-mem init-hooks. The CLI only exposes the unified init command that handles both hooks and MCP configuration. The init-hooks.ts file exists as a utility module but is not exposed as a separate command.

Suggested change
- **`git-mem init-hooks`** command — one-command setup for Claude Code hooks:
- **`git-mem init`** command — one-command setup for Claude Code hooks:

Copilot uses AI. Check for mistakes.
- Creates `.claude/settings.json` with hook registrations
- Creates `.git-mem.json` with default configuration
- Safe merge preserves other tools' hooks in `settings.json`
- `--remove` flag cleanly uninstalls git-mem hooks only
- `--scope user` for `~/.claude/settings.json` (user-wide)
- **Unified `git-mem hook <event>` command** — single entry point for all hook events, reads JSON from stdin, routes to handlers via EventBus
Comment on lines +16 to +22
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This entry describes a user-facing git-mem init-hooks command, but the current CLI only registers git-mem init (and uses init-hooks internally). If init-hooks is not meant to be a public command anymore, the changelog should reflect the actual UX (e.g., “git-mem init sets up Claude hooks …”).

Copilot uses AI. Check for mistakes.
- **DI container** (awilix) — replaces manual service instantiation across CLI, MCP, and hooks with centralized dependency injection
- **EventBus** — pub/sub event dispatch with error isolation; failing handlers don't block other handlers or crash the hook
- **`.git-mem.json` configuration** — per-project hook settings (enable/disable events, memory limits, auto-liberate threshold)
- **Hook handlers:**
- `SessionStartHandler` — loads and formats memories as markdown context
- `SessionStopHandler` — delegates to `SessionCaptureService` for 24h rolling commit scan
- `PromptSubmitHandler` — loads relevant memories for prompt context
- **Hook services:**
- `MemoryContextLoader` — loads memories with configurable limits
- `ContextFormatter` — formats memories as structured markdown
- `SessionCaptureService` — scans recent commits via `LiberateService`, extracts memories
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should reference ExtractService not LiberateService. The SessionCaptureService delegates to ExtractService (see src/application/services/SessionCaptureService.ts line 28 which injects IExtractService, and line 41 which calls extractService.extract()). There is no LiberateService in the current codebase.

Suggested change
- `SessionCaptureService` — scans recent commits via `LiberateService`, extracts memories
- `SessionCaptureService` — scans recent commits via `ExtractService`, extracts memories

Copilot uses AI. Check for mistakes.

### Changed

- CLI commands now resolve services from DI container instead of manual instantiation
- MCP tools now resolve services from DI container
Comment thread
coderabbitai[bot] marked this conversation as resolved.

## [0.2.1] - 2026-02-10

### Fixed

- MCP server ESM interop with `@modelcontextprotocol/sdk`

## [0.2.0] - 2026-02-09

### Added

- MCP server (`git-mem-mcp`) with 4 tools: remember, recall, context, liberate
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tool name should be extract not liberate. The MCP server registers four tools: remember, recall, context, and extract (as seen in src/mcp/server.ts lines 19-22). There is no liberate tool in the current implementation.

Suggested change
- MCP server (`git-mem-mcp`) with 4 tools: remember, recall, context, liberate
- MCP server (`git-mem-mcp`) with 4 tools: remember, recall, context, extract

Copilot uses AI. Check for mistakes.
- `git-mem init-mcp` command for MCP server configuration
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command name should be git-mem init not git-mem init-mcp. The CLI only exposes a unified init command that handles both hooks and MCP configuration. There is no separate init-mcp command (the init-mcp.ts file exists as a utility module but is not exposed as a separate command).

Suggested change
- `git-mem init-mcp` command for MCP server configuration
- `git-mem init` command for MCP server configuration

Copilot uses AI. Check for mistakes.
- `git-mem sync` command for syncing memories across remotes

## [0.1.0] - 2026-02-05

### Added

- Initial release
- `git-mem remember` — store memories as git notes
- `git-mem recall` — search and retrieve memories
- `git-mem context` — match staged changes against stored memories
- `git-mem liberate` — scan git history, score commits, extract memories
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The command name should be extract not liberate. Looking at src/cli.ts, the commands are: init, remember, recall, extract, context, sync, trailers, and hook. There is no liberate command in the CLI.

Copilot uses AI. Check for mistakes.
- Clean architecture (Domain → Application → Infrastructure)
- Git notes storage on `refs/notes/mem`
- Heuristic pattern extraction from conventional commits
- Optional LLM enrichment via `--enrich` flag
20 changes: 14 additions & 6 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,32 +32,36 @@ Clean architecture with three layers. Dependencies point inward only: Infrastruc

**Domain** (`src/domain/`) — Zero dependencies. Entities (`IMemoryEntity`), interfaces (`IMemoryRepository`, `INotesService`, `ITrailerService`, `IGitClient`), types (quality, lifecycle), errors (`GitMemError` hierarchy), and pure utils (deduplication).

**Application** (`src/application/`) — Depends on domain only. Three services: `MemoryService` (remember/recall CRUD), `ExtractService` (scan git history, score commits, extract patterns), `ContextService` (match staged changes against stored memories).
**Application** (`src/application/`) — Depends on domain only. Core services: `MemoryService` (remember/recall CRUD), `ExtractService` (scan git history, score commits, extract patterns), `ContextService` (match staged changes against stored memories). Hook services: `MemoryContextLoader` (loads memories with limits), `ContextFormatter` (formats memories as markdown), `SessionCaptureService` (24h rolling commit scan via ExtractService). Three event handlers: `SessionStartHandler`, `SessionStopHandler`, `PromptSubmitHandler`.

**Infrastructure** (`src/infrastructure/`) — Implements domain interfaces. `GitClient` wraps git CLI. `NotesService` reads/writes `refs/notes/mem`. `TrailerService` queries commit trailers. `MemoryRepository` persists `IMemoryEntity[]` as JSON in git notes. `HeuristicPatterns` provides regex-based extraction rules.
**Infrastructure** (`src/infrastructure/`) — Implements domain interfaces. `GitClient` wraps git CLI. `NotesService` reads/writes `refs/notes/mem`. `TrailerService` queries commit trailers. `MemoryRepository` persists `IMemoryEntity[]` as JSON in git notes. `HeuristicPatterns` provides regex-based extraction rules. `EventBus` provides pub/sub event dispatch with error isolation (failing handlers don't crash the hook).

**Entry points:**
- `src/cli.ts` — Commander.js CLI with 6 commands (remember, recall, context, extract, sync, init)
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The CLI has 8 commands, not 6. The commands are: init, remember, recall, context, extract, sync, trailers, and hook. The description is missing trailers and hook from the count and list.

Suggested change
- `src/cli.ts` — Commander.js CLI with 6 commands (remember, recall, context, extract, sync, init)
- `src/cli.ts` — Commander.js CLI with 8 commands (init, remember, recall, context, extract, sync, trailers, hook)

Copilot uses AI. Check for mistakes.
- `src/mcp-server.ts` — MCP server over stdio; `src/mcp/server.ts` creates the server and registers 4 tools
- `src/commands/hook.ts` — Unified hook entry point: reads stdin JSON, loads config, emits typed event via EventBus
- `src/commands/init.ts` — Interactive setup: hooks, MCP config, .gitignore, initial extract
- `src/commands/` — CLI command handlers
- `src/mcp/tools/` — MCP tool handlers (remember, recall, context, extract)

**Bootstrapping pattern** — Awilix DI container (`src/infrastructure/di/`). `createContainer(options?)` wires all services; CLI commands and MCP tools resolve from `container.cradle`:
**Bootstrapping pattern** — Awilix DI container (`src/infrastructure/di/`). `createContainer(options?)` wires all services; CLI commands, MCP tools, and hooks resolve from `container.cradle`:

```typescript
const container = createContainer({ logger, scope: 'remember' });
const { memoryService } = container.cradle;
```

Uses `InjectionMode.CLASSIC` (matches constructor parameter names to registration names). `ICradle` in `types.ts` defines the typed container shape with all interface references.
Uses `InjectionMode.CLASSIC` (matches constructor parameter names to registration names). `ICradle` in `types.ts` defines the typed container shape with all interface references. The container also registers the `EventBus` with three hook handlers (`session:start`, `session:stop`, `prompt:submit`) wired during creation.

**Hook event flow:** `git-mem hook <event>` → `readStdin()` → `loadHookConfig()` → `createContainer()` → `eventBus.emit(typedEvent)` → handlers return `IEventResult[]` → output to stdout (context), summary to stderr. Hooks have a 10s hard timeout and never throw — failures are caught and reported silently.
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hook failures are not “reported silently”: hookCommand writes summaries and errors to stderr (e.g., git-mem: hook failed.) even though it exits 0. Consider rewording this to reflect that hooks don’t disrupt Claude Code (exit 0 / don’t throw past the entry point), but do emit stderr diagnostics.

Suggested change
**Hook event flow:** `git-mem hook <event>``readStdin()``loadHookConfig()``createContainer()``eventBus.emit(typedEvent)` → handlers return `IEventResult[]` → output to stdout (context), summary to stderr. Hooks have a 10s hard timeout and never throw — failures are caught and reported silently.
**Hook event flow:** `git-mem hook <event>``readStdin()``loadHookConfig()``createContainer()``eventBus.emit(typedEvent)` → handlers return `IEventResult[]` → output to stdout (context), summary to stderr. Hooks have a 10s hard timeout and never throw past the entry point — failures are caught so they don't disrupt Claude Code (exit 0), but summaries and errors are reported via stderr (for example, `git-mem: hook failed.`).

Copilot uses AI. Check for mistakes.

## Testing

Uses **`node:test`** (native Node.js test runner) with **`tsx`** for TypeScript, not Jest. Tests import `describe`, `it`, `before`, `after` from `node:test` and assertions from `node:assert/strict`.

**Unit tests** (`tests/unit/`) — Mock dependencies manually (no framework). 57 tests.
**Unit tests** (`tests/unit/`) — Mock dependencies manually (no framework). 265 tests.

**Integration tests** (`tests/integration/`) — Create real temporary git repos in `os.tmpdir()`, run actual git commands, clean up in `after()`. All services instantiated against real repos. 32 tests.
**Integration tests** (`tests/integration/`) — Create real temporary git repos in `os.tmpdir()`, run actual git commands, clean up in `after()`. Hook integration tests (`tests/integration/hooks/`) spawn `git-mem hook <event>` as child processes via `tsx` binary. 46 tests.

## Environment Variables

Expand All @@ -71,6 +75,10 @@ Uses **`node:test`** (native Node.js test runner) with **`tsx`** for TypeScript,
- **`cwd` parameter**: Must be threaded through all service calls when operating on a repo that isn't the current working directory
- **Commit triage**: Weighted scoring based on conventional prefixes, decision keywords, diff size, PR merges
- **TypeScript config**: Relaxed strict mode for development (`strict: false` in tsconfig.json)
- **Hook config**: `.git-mem.json` at project root, loaded by `src/hooks/utils/config.ts`. Never throws — returns defaults on error
- **Hook stdin**: `src/hooks/utils/stdin.ts` reads JSON from stdin. Returns `{}` on TTY or parse error — hooks must never crash
- **EventBus error isolation**: Handler exceptions are caught and returned as failed `IEventResult[]` — one failing handler doesn't block others
- **Hook timeout**: 10s hard limit via `setupShutdown()` — hooks must never hang Claude Code
- Interfaces prefixed with `I` (enforced by ESLint)
- No `any` in production code (ESLint error); relaxed to warn in test files

Expand Down
149 changes: 146 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Git Mem
# git-mem

Your git history is the perfect context for AI.
It just needs to be extracted for agents....

## Why?

Your git history already contains the decisions, conventions, and gotchas that matter — git-mem extracts them and makes them available to Claude automatically.
Your git history already contains the decisions, conventions, and gotchas that matter — git-mem extracts them and makes them available to Claude automatically.

## How?

Expand All @@ -14,7 +14,7 @@ Each commit is updated with background AI metadata, which Claude can use to impr

Every **new** commit is automatically populated with the folowing metadata..
Copy link

Copilot AI Feb 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: 'folowing' should be 'following'

Suggested change
Every **new** commit is automatically populated with the folowing metadata..
Every **new** commit is automatically populated with the following metadata..

Copilot uses AI. Check for mistakes.

- **AI-Agent:** Claude/Opus-4.5
- **AI-Agent:** Claude/Opus-4.5
- **AI-Decision:** JWT over sessions — stateless API, scales horizontally
- **AI-Context:** [pattern/middleware, entity/auth-module]
- **AI-Confidence:** 0.95
Expand All @@ -34,6 +34,149 @@ git-mem init

`init` sets up hooks, MCP config, .gitignore entries, and runs an initial extract from your history.

## Quick Start

### Store a memory

```bash
git-mem remember "Use JWT for auth — decided in sprint 3" --type decision --tags auth,security
```

### Recall memories

```bash
git-mem recall --query "authentication"
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Quick Start recall example uses git-mem recall --query "...", but the CLI takes the search string as an optional positional argument (git-mem recall [query]) and does not define a --query flag. Update the example to pass the query as the argument (or add a --query option in the CLI if that’s the intended UX).

Suggested change
git-mem recall --query "authentication"
git-mem recall "authentication"

Copilot uses AI. Check for mistakes.
```

### Scan git history for knowledge

```bash
git-mem extract --since 2026-01-01
```

### Surface context for staged changes

```bash
git-mem context
```

## Claude Code Integration

git-mem integrates with [Claude Code](https://docs.anthropic.com/en/docs/claude-code) via lifecycle hooks to give Claude persistent project memory across sessions.

### How It Works

```text
Claude Code starts session
→ git-mem hook session-start
→ Loads stored memories into Claude's context

User submits prompt (optional)
→ git-mem hook prompt-submit
→ Surfaces relevant memories for the prompt

Claude Code session ends
→ git-mem hook session-stop
→ Scans commits made during session, extracts new memories
```

### Hooks

| Hook | Event | What it does |
|------|-------|-------------|
| `session-start` | `SessionStart` | Loads stored memories as markdown context |
| `session-stop` | `SessionStop` | Captures memories from recent commits via `extract` |
| `prompt-submit` | `UserPromptSubmit` | Surfaces relevant memories per prompt (disabled by default) |

### Configuration

Edit `.git-mem.json` to customize hook behavior:

```json
{
"hooks": {
"enabled": true,
"sessionStart": {
"enabled": true,
"memoryLimit": 20
},
"sessionStop": {
"enabled": true,
"autoExtract": true,
"threshold": 3
},
"promptSubmit": {
"enabled": false,
"recordPrompts": false,
"surfaceContext": true
}
}
}
```

| Option | Default | Description |
|--------|---------|-------------|
| `hooks.enabled` | `true` | Master switch for all hooks |
| `sessionStart.enabled` | `true` | Load memories on session start |
| `sessionStart.memoryLimit` | `20` | Max memories to load |
| `sessionStop.enabled` | `true` | Capture memories on session end |
| `sessionStop.autoExtract` | `true` | Auto-scan commits for memories |
| `sessionStop.threshold` | `3` | Minimum commit triage score |
| `promptSubmit.enabled` | `false` | Surface context per prompt |
| `promptSubmit.surfaceContext` | `true` | Include memories in prompt context |
Comment on lines +120 to +126
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The config table keys are inconsistent with the JSON structure shown above. Options like sessionStart.enabled / sessionStop.threshold are nested under hooks in .git-mem.json, so the documented paths should be hooks.sessionStart.enabled, hooks.sessionStop.threshold, etc. (Also promptSubmit.recordPrompts exists in the JSON but isn’t listed in the table.)

Suggested change
| `sessionStart.enabled` | `true` | Load memories on session start |
| `sessionStart.memoryLimit` | `20` | Max memories to load |
| `sessionStop.enabled` | `true` | Capture memories on session end |
| `sessionStop.autoLiberate` | `true` | Auto-scan commits for memories |
| `sessionStop.threshold` | `3` | Minimum commit triage score |
| `promptSubmit.enabled` | `false` | Surface context per prompt |
| `promptSubmit.surfaceContext` | `true` | Include memories in prompt context |
| `hooks.sessionStart.enabled` | `true` | Load memories on session start |
| `hooks.sessionStart.memoryLimit` | `20` | Max memories to load |
| `hooks.sessionStop.enabled` | `true` | Capture memories on session end |
| `hooks.sessionStop.autoLiberate` | `true` | Auto-scan commits for memories |
| `hooks.sessionStop.threshold` | `3` | Minimum commit triage score |
| `hooks.promptSubmit.enabled` | `false` | Surface context per prompt |
| `hooks.promptSubmit.recordPrompts` | `false` | Record user prompts as memories |
| `hooks.promptSubmit.surfaceContext` | `true` | Include memories in prompt context |

Copilot uses AI. Check for mistakes.

## MCP Server

git-mem also ships as an MCP server for tools that support the Model Context Protocol:

```bash
git-mem init # includes MCP setup
```
Comment on lines +132 to +134
Copy link

Copilot AI Feb 12, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

git-mem init-mcp is referenced here, but the CLI does not currently expose an init-mcp command (only init is registered in src/cli.ts). Update the docs to reflect how MCP configuration is actually generated (e.g., via git-mem init, or re-add init-mcp as a CLI command).

Copilot uses AI. Check for mistakes.

This registers `git-mem-mcp` with 4 tools: `remember`, `recall`, `context`, `extract`.

## Architecture

```text
┌─────────────────────────────────────────────┐
│ Entry Points │
│ ┌─────┐ ┌─────────┐ ┌────────────────┐ │
│ │ CLI │ │ MCP Srv │ │ Claude Hooks │ │
│ └──┬──┘ └────┬────┘ └───────┬────────┘ │
│ │ │ │ │
│ └──────────┴───────┬───────┘ │
│ │ │
│ ┌─────────┴─────────┐ │
│ │ DI Container │ │
│ │ (awilix) │ │
│ └─────────┬─────────┘ │
│ │ │
│ ┌─────────────────────┴──────────────────┐ │
│ │ Application Layer │ │
│ │ MemoryService ExtractService │ │
│ │ ContextService SessionCaptureService │ │
│ │ SessionStartHandler PromptSubmitHandler│ │
│ └─────────────────────┬──────────────────┘ │
│ │ │
│ ┌─────────────────────┴──────────────────┐ │
│ │ Domain Layer │ │
│ │ IMemoryEntity IMemoryRepository │ │
│ │ IEventBus HookEvents IHookConfig │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────┴──────────────────┐ │
│ │ Infrastructure Layer │ │
│ │ GitClient NotesService EventBus │ │
│ │ MemoryRepository HeuristicPatterns │ │
│ └────────────────────────────────────────┘ │
│ │ │
│ ┌─────────┴─────────┐ │
│ │ Git Notes │ │
│ │ refs/notes/mem │ │
│ └───────────────────┘ │
└─────────────────────────────────────────────┘
```

See the [Getting Started Guide](./docs/getting-started.md) for full CLI and MCP setup docs.

## License
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "git-mem",
"version": "0.2.1",
"version": "0.3.0",
"description": "Git-native memory layer for AI coding tools. Store decisions, context, and knowledge directly in your git repository using commit trailers and git notes.",
"bin": {
"git-mem": "dist/cli.js",
Expand Down