---
name: end-session
description: End-of-session checklist — confirm all work is committed/pushed/PR'd and that the per-session status.elevenmessenger.com ledgers (SSH access, carbon tally, prompt registry) are written before wrapping up.
---

# 🤖 end-session — leave nothing owed

Run this before wrapping up a working session. Two gates: **(A)** the work is
finished and pushed, **(B)** the public status ledgers this session touched are
written. **Check and report first; complete the mechanical parts only with the
user's OK** — never auto-merge, auto-deploy, or auto-publish (those stay the
user's call). Never echo secrets or capability/invite links (transcripts are
public — [[transcripts-are-public]]).

Work through both gates, then end with the owed/clear summary at the bottom.

## A. Work finished & pushed

1. **Tasks.** If a task list is in use, `TaskList` — any `in_progress` / `pending`
   left? Finish them, or state which are intentionally deferred and why.
2. **Working trees.** `git status` in the main checkout, and `git worktree list`
   then `git -C <wt> status` for every open worktree. Uncommitted changes →
   commit (area-prefixed: `web:`/`server:`/`docs:`…) or explain why they're left.
3. **Unpushed commits.** `git log --branches --not --remotes --oneline`. ⚠️ In a
   **shared checkout this lists every session's local branches, not just yours** —
   scope to the branches THIS session created. Anything of yours that's genuinely
   local-only → push it (feature branches, never `main`). Note a squash-merged
   branch leaves a **stale local ref** that shows here as "unpushed" even though
   the work is on `main` — that's not owed work, just delete the ref
   (`git branch -D <branch>`).
4. **Open PRs.** `gh pr list --author @me --state open`. ⚠️ This returns **all of
   your account's open PRs across every session** (the team commits under one
   author here), so **scope to the PRs THIS session opened** — the rest are other
   sessions' and not yours to touch. For each of yours: it's ready (offer to
   `gh pr merge <n> --squash --delete-branch`) or say what it's waiting on. After a
   squash-merge, delete the remote branch + `git worktree remove` the merged
   worktree (gh may fail the local step when `main` is a sibling worktree — that's
   cosmetic; the server-side merge still lands).
5. **Leftover worktrees** from already-merged branches → `git worktree remove`.
6. **Shared `main` checkout** is shared with other sessions — don't force-pull or
   mutate it; just report if it's behind after a merge.

## B. Status ledgers (status.elevenmessenger.com)

Authoritative procedures: **`docs/status.md`**. Three ledgers are **per-session**
(below). The rest — books / economics / contributors / security / milestones —
are periodic, not session-gated; mention one only if this session changed its
inputs.

### B1. SSH access ledger — REQUIRED if this session touched a fleet box
Did this session `ssh`/`scp` to the router box (`elevenbox`, `89.167.122.227`,
or any `*.11ch.at` / fleet box) — e.g. a canary deploy, a teardown, a box
inspection? If yes there **must** be a why-entry, or the public page renders the
session as **"no summary recorded"** (that state IS the enforcement).

- **Check:** is there a `web/status/ssh/<today>-*.json` covering this session's
  window? (`ls web/status/ssh/`.)
- **If missing, write** `web/status/ssh/YYYY-MM-DD-<slug>.json`:
  ```json
  { "date": "YYYY-MM-DD", "operator": "Full Name", "window": "HH:MM–HH:MM UTC (approx)", "why": "terse what-not-how summary", "refs": ["https://github.com/elevenmessenger/messenger/pull/NNN"] }
  ```
  - `operator` **must** match a handle in `web/status/ssh-operators.json`, or the
    join misses.
  - `why` is *what, not how* — never a command, credential, token, host token, or
    email. A security-sensitive session publishes as `"why": "(withheld: security)"`
    rather than vanishing. Redaction bar: `web/status/ssh/README.md`.
  - `date` + `window` are UTC and approximate; one entry may cover several
    sessions in the same working window.
- The entry rides a normal commit/PR. It only reaches the page once scp'd to the
  box (`web/status/ssh/*.json` → `/opt/lchat/status-pages/ssh/`), which happens on
  a status publish — so if this session is *already* publishing to the box, copy
  it too; otherwise the committed entry is enough and the next publish carries it.

### B2. Carbon tally
- Run `node tools/carbon-tally.mjs check`. **Silent → nothing owed.** If it says
  accrue (this machine's newest entry is >3 days old — its transcripts prune after
  ~a week, so a missed week is lost):
  1. `node tools/carbon-tally.mjs --write` (per-source cutoffs; safe to re-run),
  2. commit `web/status/carbon.json` as a **tiny standalone PR merged promptly**
     (two branches accruing the same window is the one race the cutoffs can't
     see; the contract test catches it on main),
  3. copy `web/status/carbon.json` to the box's `/opt/lchat/status-pages/`.
- `docs/status.md § Keeping the carbon tally accruing`. The check nags; the
  accrual is a judgment call you run.

### B3. Prompt registry
**Nothing auto-publishes the registry.** The only automation is the SessionStart
hook running `check`, which merely *nags* — building, **summarising**, and
uploading are all manual, so the ledger drifts whenever they're skipped.
- Run `node tools/prompt-registry.mjs check`. **Silent / "no corpus at …"** means
  the *staleness* nag is quiet — but ⚠️ **`check` only tests corpus AGE (>3 days),
  not whether recent sessions are SUMMARISED.** A corpus published <3 days ago
  without the haiku step passes silently. The visible tell is rows on
  `prompts.html` that fall back to **"FIRST PROMPT / LATEST"** instead of a
  one-line summary — those sessions still owe the **haiku summarise** step even
  though `check` is quiet. So don't trust `check` alone here: glance at
  `prompts.html` (or the built `index.json`) for un-summarised rows.
- To accrue (nagged, OR un-summarised rows exist), per `docs/status.md § The
  prompt registry`: build (`--out <dir>`) → **summarise every new session with
  haiku subagents over the REDACTED build output only** (never raw transcripts;
  ≤90-char one-liners ending in the session's most relevant GitHub URL) → re-build
  (fail-closed re-scan) → upload the corpus → commit the hash-ledger entry. It's
  heavy, creds-bound (bucket PutObject), and judgment-bound (the security sweep) —
  publishing is opt-in, so do it deliberately, never half-run it, and never
  auto-publish it from this skill.

## What this skill does NOT do
- Merge / deploy / publish without the user's OK — fleet publishes, box scps, and
  PR merges are surfaced as offers, never taken silently.
- Touch the secrets vault, echo any secret, or print an invite/capability link.
- Force-update or dirty the shared `main` checkout.

## Report
End with a tight table — each item **✅ clear** / **⚠️ owed** (with the single
action that closes it) / **— n/a this session**:

```
A1 tasks · A2 working trees · A3 unpushed · A4 open PRs · A5 worktrees · A6 main
B1 ssh ledger · B2 carbon · B3 prompt registry
```
