The /eos skill gets a close-out audit and a fabrication gate
The /eos skill runs at the end of every Claude Code session in our enterprise. It auto-generates a handoff and writes it to a D1 store so the next session’s briefing can pick up the thread. Today it got two additions that solve a pair of opposite failure modes we kept hitting at session end.
The two failure modes
Unshipped work sits. A session “felt done” but there was an open PR waiting on merge, an unpushed branch, uncommitted edits from the Edit tool, or a memory file claiming “merged in PR #N” when #N was still open. The agent wrote a confident handoff. Days later a fresh session’s briefing surfaced the residue and the work had to be rediscovered and re-contextualized.
Fabricated loose ends. The opposite problem, same session boundary. When the Captain asked “anything else?” or the skill prompted for remaining work, the agent padded the list with refactors noticed in passing, tests that could be added, adjacent cleanups, fleet-wide concerns. Well-intentioned “help” that produced noise. We had captured this in memory as “pad is worse than done.” The discipline lived in prose; the skill did not enforce it.
The two modes are structurally opposite. One misses real work; the other invents fake work. A single fix had to resolve both without producing the other.
What the change does
/eos now runs a Session Close-Out Audit before synthesizing the handoff. Six objective detection checks (A through F): uncommitted session files, unpushed commits on the current branch, unpushed commits on other branches touched this session, session-authored PRs that are review-ready, session-authored PRs with failing required checks, and memory or doc files that reference unshipped PRs with post-merge prose.
Every candidate loose-end must then pass an Anti-Fabrication Gate, which is a seven-item whitelist. If a potential loose-end is not one of the six check results or a literal Captain chat message with a verb and a subject, it does not get listed. Refactors noticed in passing, tests not requested, “we should also” items, and fleet-wide concerns are explicitly forbidden. When the audit finds nothing that passes the gate, the skill falls through to auto-save silently. Saying “we’re done” is the correct output.
When the audit finds items, it produces exactly one consolidated prompt: complete all, complete selected, or leave for next session with a per-item justification. The skill does not auto-merge PRs, does not run git add -A, does not force-push, and does not attempt to fix failing CI. Those are governance-sensitive actions that stay with the Captain.
The escape hatch has a ceiling
“Leave for next session” is the pressure-release option. Used alone it would reintroduce the first failure mode with a paper trail instead of silence. So each deferred item carries first_seen, age, and reason in the handoff. The next session’s /eos matches items by identifier and increments the age. At age >= 3, the skill refuses “leave” and forces a decision: promote to Blocked: with a real external blocker name, or kill the item outright. Filing pressure converts to closure pressure.
Why this is a skill change and not a memory entry
Memories already captured each of these rules as behavioral guidance. Agents read memory and occasionally applied it. The failure mode was that discipline kept turning into judgment calls at session end when context was long and the agent was ready to wrap up. Moving the discipline into the skill’s Step 2 makes it mechanical. The audit either produces items or it does not. The gate either passes a candidate or it kills it. There is no “I noticed this so I mentioned it” path anymore.
This is the operational move behind the end-of-session boundary: stop deciding, start measuring.