# Recipe: standardized git configuration (AG-18)

> **Audience:** any agent or maintainer setting up — or auditing — a federation
> repo's git configuration.
> **Rule:** [AG-18](../standards/AGENTS.md#AG-18). Companion to
> [`commit-signing.md`](commit-signing.md) ([AG-03](../standards/AGENTS.md#AG-03)).

Every `mgf-*` repo is wired identically, so the working tree, the ignored
surface, and the commit format are the same everywhere. Three pieces.

## 1. The canonical `.gitignore`

Present at repo root. It MUST ignore build/test artifacts, IDE config,
Claude-local settings, and — the security-load-bearing line — `my_stuff/`:

```gitignore
# Local secrets / tokens — NEVER committed (AG-18, PKG-03, SECURITY)
my_stuff/

# IDE
.idea/
.vscode/
*.swp

# Local Claude overrides
.claude/settings.local.json
```

…plus the language block (Python `__pycache__/`, `dist/`, `*.egg-info/`,
`.venv/`…; Zig `.zig-cache/`, `zig-out/`, `zig-pkg/`…). New repos inherit the
full file from the cookiecutter; existing repos run:

```sh
mgf-fed catch-up --apply     # appends any MISSING standard ignore lines
```

`catch-up --apply` only *appends* missing lines — it never reorders or removes
a repo's own entries.

### Why `my_stuff/` is non-negotiable

`my_stuff/` is the repo-root home for local credentials — the devpi publish
password at `my_stuff/tokens/devpi_password.txt` (PKG-03; needed only for a
manual publish — CI publishes via the tag-scoped `devpi_password` org secret,
and install is **anonymous**), SSH keys under `my_stuff/ssh_key/`. Committing it leaks a credential, so the ignore is a
SECURITY boundary, not a preference. `mgf-fed app-doctor` fails a repo whose
`.gitignore` does not ignore `my_stuff/`.

## 2. The `.gitmessage` commit template

Wired once per clone so commit drafts carry the AG-03 trailers:

```sh
git config commit.template .gitmessage
```

## 3. Identity

```sh
git config user.name  "Bassam Alsanie"
git config user.email "bassam@magogi.org"
```

## 4. The `prepare-commit-msg` hook (AG-03 enforcement)

The `.gitmessage` template (§2) is consulted only for *interactive* commits —
`git commit -m` (the common agent/scripted path) bypasses it, so the AG-03
`Signed-off-by` is easy to drop. The committed `.githooks/prepare-commit-msg`
hook closes that gap: it appends the human signoff **idempotently** on every
commit, including `-m`. Wire it once per clone:

```sh
git config core.hooksPath .githooks
```

The hook adds only the *constant* human `Signed-off-by` (derived from
`user.name`/`user.email`); the model-specific `Co-Authored-By` stays
agent-supplied. The **authoritative** enforcement — a CI/PR `commit-trailers`
gate that fails on any commit missing *either* trailer (independent of local
config; reference checker `scripts/check_commit_trailers.py`) — is tracked in
[mgf-common FEEDBACK PAPER-102](https://codeberg.org/magogi-admin/mgf-common/src/branch/main/FEEDBACK.md).

## One-liner for a fresh clone

```sh
git config commit.template .gitmessage
git config core.hooksPath  .githooks    # AG-03 signoff hook (§4)
git config user.name  "Bassam Alsanie"
git config user.email "bassam@magogi.org"
mgf-fed catch-up --apply      # ensure .gitignore carries the standard lines
```

## Verify

```sh
git check-ignore my_stuff/        # → "my_stuff/"  (ignored)   ✓
git config --get commit.template  # → .gitmessage              ✓
git config --get core.hooksPath   # → .githooks                ✓
mgf-fed app-doctor                 # → AG-18 checks pass
```
