Manage git-backed memory repos. Load this skill when working with git-backed agent memory, setting up remote memory repos, resolving sync conflicts, or managing memory via git workflows.
68
81%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Low
Low-risk findings worth noting
Agents with the git-memory-enabled tag have their memory blocks stored in git repositories accessible via the Letta API. This enables version control, collaboration, and external editing of agent memory.
Features:
$LETTA_BASE_URL/v1/git/<agent-id>/state.gitmemory/system/*.md for system blocksWhen memfs is enabled, the Letta Code CLI automatically:
git-memory-enabled tag to the agent (triggers backend to create the git repo)~/.letta/agents/<agent-id>/memory/ (git root is the memory directory)memory/.git/config (so git push/git pull work without auth ceremony)letta.agentId, user.name, user.email) so direct git commit from the agent's shell attributes correctly to the agent — not the operator's global git identitygit status and reminds you (the agent) to commit/push if dirtyIf any of these steps fail, you can replicate them manually using the sections below.
The harness configures a per-repo credential helper during clone and refreshes it on pull/startup. This local setup is the default and recommended approach.
Why this matters: host-level global credential helpers (e.g. installed by other tooling) can conflict with memfs auth and cause confusing failures.
Important: Always use single-line format for credential helpers. Multi-line helpers can break tools that parse git config --list line-by-line.
cd ~/.letta/agents/<agent-id>/memory
# Check local helper(s)
git config --local --get-regexp '^credential\..*\.helper$'
# Reconfigure local helper (e.g. after API key rotation) - SINGLE LINE
git config --local credential.$LETTA_BASE_URL.helper '!f() { echo "username=letta"; echo "password=$LETTA_API_KEY"; }; f'If you suspect global helper conflicts, inspect and clear host-specific global entries:
# Inspect Letta-related global helpers
git config --global --get-regexp '^credential\..*letta\.com.*\.helper$'
# Example: clear a conflicting host-specific helper
git config --global --unset-all credential.https://api.letta.com.helperFor cloning a different agent's repo, prefer a one-off auth header over global credential changes:
AUTH_HEADER="Authorization: Basic $(printf 'letta:%s' "$LETTA_API_KEY" | base64 | tr -d '\n')"
git -c "http.extraHeader=$AUTH_HEADER" clone "$LETTA_BASE_URL/v1/git/<agent-id>/state.git" ~/my-agent-memoryThe harness installs a git pre-commit hook that validates .md files under memory/ before each commit. This prevents pushes that the server would reject.
Rules:
.md file must have YAML frontmatter (--- header and closing ---)description (non-empty string)read_only is a protected field: you (the agent) cannot add, remove, or change it. Files with read_only: true cannot be modified at all. Only the server/user sets this field.Valid file format:
---
description: What this block contains
---
Block content goes here.If the hook rejects a commit, read the error message — it tells you exactly which file and which rule was violated. Fix the file and retry.
In addition to pushing to the Letta server, you can push every commit to a second git remote — e.g. a private GitHub repo — so you have a backup or a copy you can browse with regular tools.
Via the slash command (recommended):
/memory-repository set git@github.com:you/my-memory.git
/memory-repository status
/memory-repository push # force a push now, e.g. after a network failure
/memory-repository unset # stop pushingHow it works:
/memory-repository set <url> writes the URL to letta.memoryRepository.url in the memfs repo's local .git/config and installs a post-commit hook.letta.memoryRepository.url and asynchronously pushes to it in the background. Commits are never blocked by push failures..git/memory-repository-push.log — visible via /memory-repository status.Auth: uses your existing git credentials — SSH keys, credential helpers, or tokens in the URL. Letta does not store tokens for this feature. If you're pushing to GitHub, SSH is easiest.
Manual equivalent (without the slash command):
cd ~/.letta/agents/<agent-id>/memory
git config --local letta.memoryRepository.url git@github.com:you/my-memory.git
# Hook is installed automatically by the CLI on startup; no manual install needed.# Clone agent's memory repo
git clone "$LETTA_BASE_URL/v1/git/<agent-id>/state.git" ~/my-agent-memory
# View memory blocks
ls ~/my-agent-memory/memory/system/
cat ~/my-agent-memory/memory/system/human.mdIf the harness /memfs enable failed, you can replicate it:
AGENT_ID="<your-agent-id>"
AGENT_DIR=~/.letta/agents/$AGENT_ID
MEMORY_REPO_DIR="$AGENT_DIR/memory"
# 1. Add git-memory-enabled tag (IMPORTANT: preserve existing tags!)
# First GET the agent to read current tags, then PATCH with the new tag appended.
# The harness code does: tags = [...existingTags, "git-memory-enabled"]
curl -X PATCH "$LETTA_BASE_URL/v1/agents/$AGENT_ID" \
-H "Authorization: Bearer $LETTA_API_KEY" \
-H "Content-Type: application/json" \
-d '{"tags": ["origin:letta-code", "git-memory-enabled"]}'
# 2. Clone the repo into memory/
mkdir -p "$MEMORY_REPO_DIR"
git clone "$LETTA_BASE_URL/v1/git/$AGENT_ID/state.git" "$MEMORY_REPO_DIR"
# 3. Configure local credential helper (single-line format required)
cd "$MEMORY_REPO_DIR"
git config --local credential.$LETTA_BASE_URL.helper '!f() { echo "username=letta"; echo "password=$LETTA_API_KEY"; }; f'# 1. Edit block via API (or use memory tools)
# 2. Pull to get changes (webhook creates commit automatically)
cd ~/.letta/agents/<agent-id>/memory
git pullChanges made via the API are automatically committed to git within 2-3 seconds.
cd ~/.letta/agents/<agent-id>/memory
# 1. Edit files locally
echo "Updated info" > system/human.md
# 2. Commit and push
git add system/human.md
git commit -m "fix: update human block"
git push
# 3. API automatically reflects changes (webhook-triggered, ~2-3s delay)When both API and git have diverged:
cd ~/.letta/agents/<agent-id>/memory
# 1. Try to push (will be rejected)
git push # -> "fetch first"
# 2. Pull to create merge conflict
git pull --no-rebase
# -> CONFLICT in system/human.md
# 3. View conflict markers
cat system/human.md
# <<<<<<< HEAD
# your local changes
# =======
# server changes
# >>>>>>> <commit>
# 4. Resolve
echo "final resolved content" > system/human.md
git add system/human.md
git commit -m "fix: resolved conflict in human block"
# 5. Push resolution
git push
# -> API automatically updates with resolved content# Create file in system/ directory (automatically attached to agent)
echo "My new block content" > system/new-block.md
git add system/new-block.md
git commit -m "feat: add new block"
git push
# -> Block automatically created and attached to agent# Remove file from system/ directory
git rm system/persona.md
git commit -m "chore: remove persona block"
git push
# -> Block automatically detached from agent~/.letta/agents/<agent-id>/
├── .letta/
│ └── config.json # Agent metadata
└── memory/ # Git repo root
├── .git/ # Git repo data
└── system/ # System blocks (attached to agent)
├── human.md
└── persona.mdSystem blocks (memory/system/) are attached to the agent and appear in the agent's system prompt.
git-memory-enabled tagClone fails with "Authentication failed":
git -C ~/.letta/agents/<agent-id>/memory config --local --get-regexp '^credential\..*\.helper$'git config --global --get-regexp '^credential\..*letta\.com.*\.helper$'curl -u letta:$LETTA_API_KEY $LETTA_BASE_URL/v1/git/<agent-id>/state.git/info/refs?service=git-upload-packPush/pull doesn't update API:
git-memory-enabled tagHarness setup failed (no .git/ after /memfs enable):
LETTA_DEBUG=1)Can't see changes immediately:
git pull to get latest API changesgit fetch to check remote without merging051b47f
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.