Committing code auto-writes to memory (git-commit/push triggers memory record + flush)¶
Angelo › agent-memory › Phase 3: Git Integration
Type: Decision · Status: active · Created: 2026-06-17
Tags: decision,hooks,automation,git,commit,claude-code,memory-protocol
Goal: when the user asks to commit/push code, the system should automatically (a) record what happened to the memory tree and (b) ensure memory files land in git with the push — with no agent asking for confirmation.
Design: two layers on the same git commit/git push trigger¶
Layer 1 — Content (a rule, not a script). Deciding what happened and whether it's worth recording is a judgment only the main agent can make, so this is encoded as a rule, not a hook. A new "Committing Code Writes to Memory" section in the memory protocol instructs the agent: when asked to commit/push, FIRST record one concise entry (agent picks the type — checkpoint/decision/experiment/note), git-pinned to the changed files, THEN run git. It is explicitly automatic — the agent must not ask permission to record. It skips trivial/safety/WIP commits and never duplicates an entry already written that session. Mirrored into all three rule files: .cursor/rules/memory.mdc, angelo_cli/data/rules/memory.mdc, angelo_cli/data/claude/rules/memory.md.
Why a rule and not a beforeShellExecution hook: a before-shell hook fires a separate lightweight model that can only allow/deny the command — it cannot make the main agent compose and record an entry, nor sequence "record then git." The agent ordering its own actions is the only way to get the "before" timing the user wanted.
Layer 2 — Plumbing (deterministic hooks + CLI). A git commit/push also fires a hook that flushes pending .memory/ files into git so the just-written entry rides up with the push:
- Cursor: afterShellExecution hook, matcher git\s+(commit|push), runs angelo memory commit --quiet.
- Claude Code: PostToolUse/Bash hook → angelo-claude-hook post-bash, which filters the command for git commit/push and calls the same logic.
New CLI angelo memory commit (--no-push, --quiet, --dry-run) and shared commit_dirty_memory() in angelo_cli: discovers modified/untracked .memory/ files via git status --porcelain -z (gitignored sidecars like .memory/active-sessions/ excluded automatically; deletions skipped), then commits them in isolation via MemoryCommitter. Always exits 0 so it can never break the triggering shell command.
memory/commit.py refactor: extracted _commit_files_locked (isolated add+commit of given paths, never touches the user's staged changes) and added synchronous commit_now(paths) that the CLI uses (the in-process debounce queue lives in the MCP server, so the CLI scans the working tree itself). Safe-auto-push is unchanged — it only pushes when every unpushed commit is memory-mcp-authored, so user WIP is never pushed; the code commit/push carries the separate memory-mcp commit up together.
End-to-end flow on "commit and push"¶
Agent records what happened (rule) → git commit (code) → hook commits the memory entry as a memory-mcp commit → git push → both travel to the remote together.
Caveat¶
Code and memory land in two separate commits (user-authored code commit + memory-mcp memory commit) that push together — deliberately kept separate to preserve the auto-push safety invariant (memory files must be memory-mcp-authored). Merging into one physical commit would break that model.
Verification¶
angelo memory commit --dry-runcorrectly listed the one tracked dirty entry and excluded the gitignored session sidecar.- Claude
post-bashhandler: non-git command is a silent no-op (exit 0); git-command regex matches commit/push and not status/ls. - 7 existing committer tests (
test_commit_integrity.py,test_commit_denylist.py) still pass after the refactor.
Referenced files¶
memory/commit.py@56695fdangelo_cli/__init__.py@56695fdangelo_cli/claude_hooks.py@56695fd- .cursor/hooks.json@56695fd
- .cursor/rules/memory.mdc@56695fd
angelo_cli/data/hooks.json@56695fdangelo_cli/data/claude/settings.json@56695fd
Source: memory entry deci-3cc410ab.