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
12 changes: 11 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- **Documentation repositioning** — README and getting-started now lead with AI metadata tracking, memory as "level up"

## [0.4.0] - 2026-02-15
## [0.5.0] - 2026-02-16

### Added

Expand All @@ -31,12 +31,22 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Detects memory type (decision, gotcha, convention, fact) from patterns
- Infers tags from conventional commit scope and file paths
- Adds AI-Agent, AI-Model, AI-Confidence, AI-Lifecycle, AI-Memory-Id trailers
- **Multi-provider LLM enrichment** (GIT-110) — OpenAI, Gemini, Ollama alongside Anthropic; auto-detected from env vars or configured in `.git-mem.yaml`
- **Multi-agent detection** (GIT-121) — auto-detects Claude Code and Codex from env vars, resolves model from config files (session JSONL, config.toml)
- **`git mem trailers` command** (GIT-71) — inspect AI-* trailers on commits, query across history, list distinct keys

### Fixed

- Edge cases in commit-msg hook (empty messages, missing env vars)
- Duplicate Agent/Model trailers prevention
- Hook chaining — all hooks now install by default
- **Hook LLM config passthrough** (GIT-122) — hook command now forwards `llm` config from `.git-mem.yaml` to DI container
- **Init MCP** — support source-checkout local server resolution (GIT-80)
- **Init push semantics** — preserve default push semantics for notes refs (GIT-117)
- **Circular error references** — in logger and handlers (GIT-109)
- **Git root resolution** — for init paths + Windows test compat (GIT-108)
- **Undefined content** — handle undefined content in memory query (GIT-96)
- **Windows compat** — PowerShell-safe lint globs (GIT-118), cross-platform test commands (GIT-119)

## [0.3.0] - 2026-02-12

Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Clean architecture with three layers. Dependencies point inward only: Infrastruc
**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)
- `src/cli.ts` — Commander.js CLI with 8 commands (remember, recall, context, extract, sync, init, trailers, hook)
- `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
Expand All @@ -51,7 +51,7 @@ 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. The container also registers the `EventBus` with three hook handlers (`session:start`, `session:stop`, `prompt:submit`) wired during creation.
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 five hook handlers (`session:start`, `session:stop`, `prompt:submit`, `commit:msg`, `post:commit`) 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.

Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

Track AI contributions in your git history.

![AI commit metadata](git-mem.png)

## Why?

AI writes code now. Your commits should show when, which agent, and which model.
Expand Down
48 changes: 45 additions & 3 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ Options:
- `--commit-count <n>` — Max commits to process
- `--dry-run` — Preview without writing
- `--threshold <n>` — Interest score threshold (default: 3)
- `--enrich` — Enable LLM enrichment (requires `ANTHROPIC_API_KEY`)
- `--enrich` — Enable LLM enrichment (requires an LLM provider API key)

### context

Expand All @@ -164,6 +164,24 @@ git mem sync --push # push only
git mem sync --pull # pull only
```

### trailers

Inspect AI-* trailers on commits.

```bash
git mem trailers # show trailers on HEAD
git mem trailers abc123 # show trailers on specific commit
git mem trailers --query AI-Decision # search across history
git mem trailers --keys # list all distinct AI-* trailer keys
```

Options:
- `--query <key>` — Search for trailer key across history (e.g. `AI-Decision`)
- `--since <date>` — Filter commits after date
- `--keys` — List all distinct AI-* trailer keys in the repo
- `-n, --limit <n>` — Max commits to search
- `--json` — Output as JSON

---

## Using Claude Code?
Expand All @@ -177,6 +195,8 @@ If you use Claude Code, git-mem can do more than just add trailers & notes — i
| **SessionStart** | Loads stored memories into Claude's context on startup |
| **Stop** | Extracts knowledge from commits made during the session |
| **UserPromptSubmit** | Surfaces relevant memories per prompt (disabled by default) |
| **PostCommit** | Records AI agent and model metadata on each commit |
| **CommitMsg** | Analyzes commit message and adds AI-* trailers (with optional LLM enrichment) |

These hooks read the AI trailers from your commits and build a searchable memory layer that Claude can query.

Expand All @@ -195,13 +215,35 @@ hooks:
promptSubmit:
enabled: false
surfaceContext: true
commitMsg:
enabled: true
enrich: false # set true + provide LLM API key for enriched extraction
enrichTimeout: 8000
postCommit:
enabled: true
```


## Environment Variables

| Variable | Required | Description |
|----------|----------|-------------|
| `ANTHROPIC_API_KEY` | Only for `--enrich` | Anthropic API key for LLM enrichment during extract. Get one at [console.anthropic.com](https://console.anthropic.com/). |
| `ANTHROPIC_API_KEY` | For Anthropic LLM | Anthropic (Claude) API key |
| `OPENAI_API_KEY` | For OpenAI LLM | OpenAI API key (requires `npm install openai`) |
| `GOOGLE_API_KEY` / `GEMINI_API_KEY` | For Gemini LLM | Google Gemini API key (requires `npm install @google/generative-ai`) |
| `OLLAMA_HOST` | For Ollama | Ollama server URL (default: `http://localhost:11434`) |
| `GIT_MEM_LLM_PROVIDER` | No | Force provider: `anthropic`, `openai`, `gemini`, `ollama` |

Only one provider is needed. If `--enrich` is used without any LLM API key, git-mem falls back to heuristic extraction with a warning.

### LLM Configuration

If `--enrich` is used without an API key, git-mem falls back to heuristic extraction only.
You can also configure the LLM provider in `.git-mem/.git-mem.yaml`:

```yaml
llm:
provider: openai # auto-detected from env vars if omitted
model: gpt-4o # uses provider default if omitted
intentModel: gpt-4o-mini
baseUrl: http://localhost:11434 # for ollama
```
Binary file added git-mem.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "git-mem",
"version": "0.4.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.",
"version": "0.5.0",
"description": "Add AI metadata to git commits automatically. Tracks agent, model, and decisions via commit trailers and git notes.",
"bin": {
"git-mem": "dist/cli.js",
"git-mem-mcp": "dist/mcp-server.js"
Expand Down
7 changes: 5 additions & 2 deletions tests/integration/hooks/hook-commit-msg.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,10 @@ describe('Integration: hook commit-msg', () => {
it('should detect Claude Code agent from CLAUDECODE env var', () => {
delete process.env.GIT_MEM_AGENT;
process.env.CLAUDECODE = '1';
process.env.ANTHROPIC_MODEL = 'claude-opus-4-5-20251101';
// Use GIT_MEM_MODEL (highest priority) rather than ANTHROPIC_MODEL,
// because detectClaudeModel() reads session JSONL files when CLAUDECODE
// is set, which can find real sessions in the dev environment.
process.env.GIT_MEM_MODEL = 'claude-opus-4-5-20251101';

const commitMsg = 'feat: claude code commit';
const msgPath = createCommitMsgFile(repoDir, commitMsg);
Expand All @@ -457,7 +460,7 @@ describe('Integration: hook commit-msg', () => {
modifiedMsg.includes('Claude-Code') || modifiedMsg.includes('claude-code'),
'Agent should be Claude Code variant',
);
assert.ok(modifiedMsg.includes('AI-Model: claude-opus-4-5-20251101'), 'Should use ANTHROPIC_MODEL');
assert.ok(modifiedMsg.includes('AI-Model: claude-opus-4-5-20251101'), 'Should use GIT_MEM_MODEL');
});
});

Expand Down