# Git Operations Runbook

Live operational document. Refer to this before every git operation. Update it when procedures change.

## Architecture

```
origin   gitea:jso/agentmemory.git               Private dev (everything)
github   github-rrs:robotrocketscience/agentmemory.git   Public (filtered)
```

SSH key `~/.ssh/id_rrs` authenticates as `robotrocketscience` via the `github-rrs` host alias in `~/.ssh/config`.

## Daily Development

```bash
# Work on main or feature branch
git add <files>
git commit -m "prefix: description"

# Push to Gitea (always safe, private)
git push origin main
```

Commit prefixes enforced by pre-commit hook: `feat:`, `fix:`, `refactor:`, `docs:`, `chore:`, `test:`, `exp:`.

## Publishing to GitHub

The publish script filters out private files (experiments, benchmarks, dev config) before pushing. It creates a temporary filtered commit, force-pushes it, then hard-resets back to the original HEAD.

```bash
git fetch github                    # REQUIRED: prevents stale-info rejection
bash scripts/publish-to-github.sh
```

### What the script does

1. Reads `.github-exclude` patterns
2. Collects matching tracked files (typically ~250-300 files)
3. Saves current HEAD hash
4. Creates a temporary commit with excluded files removed from the index
5. Force-pushes the filtered commit to `github` remote
6. Hard-resets local state to saved HEAD (restores all files)

### Verification after publish

```bash
# Confirm local state is intact
git ls-files TODO.md CLAUDE.md .mcp.json experiments/__init__.py
# All four should appear. If any are missing, the reset failed.

# Confirm GitHub has the right content
git log --oneline github/main -3
```

### If the reset fails

The publish script uses `git reset --hard $ORIG_HEAD`. If it fails mid-push:

```bash
git reflog                     # Find the pre-publish HEAD
git reset --hard <hash>        # Restore
git ls-files TODO.md           # Verify excluded files are tracked
```

## Releasing a Version

### 1. Prepare

```bash
# Ensure clean state
git status                     # Must be clean
uv run pytest tests/ -x -q     # Tests pass
uv run pyright src/agentmemory/ # Types clean
```

### 2. Bump

```bash
# Edit pyproject.toml: version = "X.Y.Z"
# Edit CITATION.cff: version = "X.Y.Z"
# Add CHANGELOG.md entry under ## [X.Y.Z] - YYYY-MM-DD
uv lock
git add pyproject.toml uv.lock CHANGELOG.md CITATION.cff
git commit -m "chore: bump version to X.Y.Z"
```

### 3. Push and publish

```bash
git push origin main
bash scripts/publish-to-github.sh --tag vX.Y.Z
```

### 4. Verify

```bash
# GitHub release exists
gh api repos/robotrocketscience/agentmemory/releases/latest --jq '.tag_name'

# PyPI has the version (may take 1-2 min)
curl -s "https://pypi.org/pypi/agentmemory-rrs/json" | python3 -c "import sys,json; print(json.load(sys.stdin)['info']['version'])"

# Local state intact
git ls-files TODO.md CLAUDE.md .mcp.json experiments/__init__.py
```

## What NOT To Do

- **Never `git push github` directly.** Always use `scripts/publish-to-github.sh`. Direct push sends private files.
- **Never `git rm --cached` excluded files manually.** The publish script handles this. Manual removal breaks Gitea tracking.
- **Never commit the filtered-publish commit to Gitea.** If you see `chore: filtered publish` in your local log, something went wrong. Check reflog and reset.

## Files That Must Stay Tracked (for Gitea) but Not Reach GitHub

Defined in `.github-exclude`:
- `TODO.md`, `CLAUDE.md`, `.mcp.json`, `.github-exclude`
- `experiments/` (entire directory)
- `benchmarks/` (entire directory)
- `docs/PRIVATE_*.md`

## Remotes Reference

| Remote | URL | SSH Key | Account |
|---|---|---|---|
| `origin` | `gitea:jso/agentmemory.git` | `~/.ssh/id_ed25519` | Gitea (jso) |
| `github` | `github-rrs:robotrocketscience/agentmemory.git` | `~/.ssh/id_rrs` | GitHub (robotrocketscience) |

## PyPI Trusted Publisher

Configured on pypi.org for `agentmemory-rrs`:
- Owner: `robotrocketscience`
- Repository: `agentmemory`
- Workflow: `publish.yml`

If this is not yet updated from robot-rocket-science, update at https://pypi.org/manage/project/agentmemory-rrs/settings/publishing/

## Changelog

- **2026-04-20**: Created. Documented filtered-publish workflow, hard-reset recovery, and lessons from 3 failed publish attempts during GitHub account migration.
- **2026-04-20**: Added `git fetch github` as mandatory step before publish. Without it, `--force-with-lease` rejects due to stale remote tracking info.
