---
description: Close out a Duty Free Professor session — doc gates, NOW block, issues sweep, diary, handoff, /plan
---

Run the project checkpoint. This extends the server `/checkpoint` (`/srv/.claude/commands/`)
with four duties Decision 11 added (build plan §3c); it loads only when the session's cwd is
`/srv/apps/dutyfreeprofessor`, which is why sessions open there.

## 1. Record the facts (mechanical, same as the server command)

```bash
bash /srv/.logging/hooks/checkpoint.sh command "$PWD"
```

## 2. The four project duties

1. **Rewrite the NOW block in `brief.md`** in place (the six lines under `## NOW`): phase,
   accepted scope, deadline, live version (must equal `APP_VERSION` in `main/app/version.py`),
   public airports (from `docker exec dutyfreeprofessor-app python -m app.cli shops`, codes
   not a count), next milestone. Nothing else in `brief.md` changes at a checkpoint.
2. **Sweep the running list**: `python3 main/scripts/items.py sweep` lists every open item by
   owner with its age. Resolve what your session actually closed
   (`python3 main/scripts/items.py resolve <id> --by "Stream X" --note "<commit or proof>"`),
   add what you found (`items.py add --kind issue|decide|do ...`), and read what rian decided
   since the item was raised (`items.py list --decisions`) so your handoff reflects it. The two
   markdown registers (`.logs/issues.md`, `.logs/decisions-for-rian.md`) are regenerated by the
   script; never edit them by hand.
3. **Run the doc gates** and fix what they name before you write anything else:
   ```bash
   python3 main/scripts/docmap.py --write && bash main/docs-check.sh
   ```
   A FAIL is yours to clear now; a warn is yours if it names a doc you changed or a source
   you changed. Never type a number a generated block or `/api/stats` can supply.
4. **Read what rian said to Claude** on the running list, and act on it or record it:
   ```bash
   docker exec dutyfreeprofessor-app python -m app.cli discussion inbox --for claude --since <date of the last handoff entry>
   ```
   A comment naming `@claude` on `/issues` is rian talking to the next session (T10); it
   notifies nobody. Answer in the thread (as yourself, in an owner session) or in the handoff.
5. **Write the diary entry** by hand only if the hook's mechanical entry misses something a
   reader must know (a verification that ran, a run that was killed); otherwise leave it.

## 3. The handoff entry (the part no script can write)

Prepend to `.logs/handoff.md`, below the title, above the newest entry, **25 lines at most**:

```markdown
## YYYY-MM-DD — <what this session actually accomplished, one line>

**Landed:** finished and verified, and how (test names, curl, a number from /api/stats).
**In flight:** anything half-done, with enough to resume safely.
**Next:** the single most useful thing for the next session.
**Blocked/needs rian:** decisions, sudo, credentials; each also added to the running list
(`python3 main/scripts/items.py add --kind decide ... --assumption "<what you proceeded under>"`).
```

State, not summary. Explain a mechanism in `main/docs/` and link it; the handoff is not its
home. If a bug shipped, its test is in `main/tests/` before this entry says "fixed".

## 4. Update `/plan`

Every task you touched has its status set, with a note that says what proves it:

```bash
python3 main/scripts/plan-set.py <ID> done "Stream <X>" --note "<what proves it>"
```

Add a line under `## Unreleased` in `main/CHANGELOG.md` for anything a user or the client
would notice; do not bump the version (rian does, at the deploy checkpoint, and the gate
checks that `brief.md`, `CHANGELOG.md` and `version.py` agree).

## 5. Report back

One or two lines to the user: what was recorded, what the gates said, what the next session
picks up.
