---
title: Checkout Footer Syntax
read_when:
  - building or modifying PR body footer content
  - debugging erk pr check validation failures
  - working on the submit pipeline or git-pr-push command
tripwires:
  - action: "writing checkout footer with issue number from .erk/impl-context/plan-ref.json"
    warning: "Use PR number (from create_pr result), NOT issue number. The checkout command requires a PR number. Issue numbers in checkout footers cause erk pr check validation failures."
  - action: "writing gh pr checkout in a PR footer"
    warning: "The checkout footer uses `erk pr checkout <number> --script`, NOT `gh pr checkout`. The footer format has changed."
---

# Checkout Footer Syntax

## Why the Footer Exists

Every erk PR includes a standardized footer that lets reviewers checkout the PR into a fresh worktree with a single command. This footer is validated by `erk pr check` and generated by multiple code paths (submit pipeline, git-pr-push command, remote implementation workflow).

## The Two-Phase Create-Then-Update Pattern

The footer cannot be included in the initial PR body because **the PR number is not known until `create_pr()` returns**. The footer must contain `erk pr checkout <pr_number>`, creating a chicken-and-egg problem. The solution across all code paths is:

1. Create the PR with body content (including `Closes` reference — see below)
2. Call `build_pr_body_footer()` with the returned PR number
3. Append the footer via `update_pr_body()`

<!-- Source: packages/erk-shared/src/erk_shared/gateway/github/pr_footer.py, build_pr_body_footer -->

See `build_pr_body_footer()` in `packages/erk-shared/src/erk_shared/gateway/github/pr_footer.py` for the canonical footer generation.

**Why `Closes` must be in the initial body, not the footer update:** GitHub's `willCloseTarget` field is set at PR creation time and is NOT updated when the body is edited afterward. The `Closes #N` reference is therefore placed in the initial `create_pr()` body, while the checkout command is appended via a subsequent `update_pr_body()` call.

## PR Number vs Issue Number

The single most common agent mistake is using the issue number from `.erk/impl-context/plan-ref.json` instead of the PR number in the checkout command. These are different GitHub entities:

| Source                            | Use for checkout footer?    | Why                                                  |
| --------------------------------- | --------------------------- | ---------------------------------------------------- |
| `create_pr()` return value        | Yes — this is the PR number | `erk pr checkout` requires a PR number               |
| `.erk/impl-context/plan-ref.json` | Never                       | Plan issue number != PR number; validation will fail |

```python
# WRONG: Using issue number
footer = f"erk pr checkout {issue_data['issue_number']} --script"

# WRONG: Using gh pr checkout (outdated command)
footer = f"gh pr checkout {pr_number}"
```

## PR Body Three-Part Structure

PR bodies have a header/content/footer structure, each with distinct purposes:

| Section | Delimiter            | Purpose                                                |
| ------- | -------------------- | ------------------------------------------------------ |
| Header  | Start of body        | Metadata lines (`**Plan:**`, `**Remotely executed:**`) |
| Content | After header         | PR description and implementation details              |
| Footer  | After last `\n---\n` | Closing reference + checkout command                   |

<!-- Source: packages/erk-shared/src/erk_shared/gateway/github/pr_footer.py, extract_footer_from_body -->

The footer is extracted by splitting on the **last** `\n---\n` delimiter. See `extract_footer_from_body()` in the `pr_footer` module. This means markdown horizontal rules in the body content must not use bare `---` on its own line, or the footer parser will split incorrectly.

## Cross-Repo Support

When `plans_repo` is configured (in `.erk/config.toml`), the closing reference uses cross-repo syntax: `Closes owner/repo#123` instead of `Closes #123`. The checkout command itself is unaffected — it always uses the local repo's PR number.

## Validation

<!-- Source: src/erk/cli/commands/pr/check_cmd.py, pr_check -->
<!-- Source: packages/erk-shared/src/erk_shared/gateway/pr/submit.py, has_checkout_footer_for_pr -->

`erk pr check` validates the footer by calling `has_checkout_footer_for_pr()`, which matches the pattern `erk pr checkout <pr_number>\b` against the PR body. The validation confirms the number in the footer matches the actual PR number — a footer with a wrong number (e.g., from an issue) will fail even though the format looks correct.

## Related Documentation

- [PR Validation Rules](pr-validation-rules.md) — Complete validation ruleset including checkout footer checks
