Building Clinch

Designed and built /clinch, an end-of-session ritual that surfaces loose ends, proposes memory writes, and walks every dirty repo through verify-commit-push with per-repo confirmation.

I keep walking away from Claude Code sessions with dirt. A handful of repos modified, memory writes half-applied, an abandoned thread or two, sometimes a workshop-worthy debugging story I never write up. The next session opens to a git status I have to triage before I can do anything useful, and the lesson worth remembering is gone.

So I built /clinch — an end-of-session ritual skill that walks the close in one pass.

The grill

I asked Claude to grill me on it, branch by branch. My starting plan was four bullets: update memory and skills from the conversation, ensure all touched repos are clean, surface pending actions and detours, suggest a workshop ingest if relevant.

Trigger. I started thinking pure slash command. Claude pushed back: I forget to wrap up, that’s the whole problem, so a manual command alone won’t fix it. We landed on slash command plus a soft SessionEnd hook that prints a one-line nudge if any repo is dirty when the session closes. Just a reminder for next time.

Repo discovery. First thought: scan the four projects in my reference_projects.md memory. Then I actually checked /projects/ and found 13 repos. Memory had drifted. We threw out the documented-list approach and went with: glob /projects/*/.git, run git status --porcelain and an unpushed-commits check on each. Stateless, no dependency on me keeping memory in sync, and it surfaces stale dirt from previous sessions too.

The backlog question. Claude proposed Clinch produce a “suggestions” file for skill and CLAUDE.md edits it didn’t want to apply automatically — let future me look at them. I pushed back: I worry about adding future-me work I’m not sure how to reach. Resolve everything in the current pass — apply, edit, or skip — and let unwanted items die. He wrote that as a feedback memory. Generalises beyond Clinch.

Build verification. I’d missed it. Claude went and read five comparable skills (session-retrospective, wrapup, wrap-session, finish-the-day, the MindStudio learnings-loop pattern) and noticed wrapup runs build/test before pushing. My workshop and life sites auto-deploy from main to Vercel — pushing a broken build breaks live sites. So we added: detect a typecheck or build script, run it on non-docs-only diffs, abort that repo’s push on failure. Skip silently when not detectable.

What’s in it

The skill itself is in ~/claude-config/skills/clinch/SKILL.md. It runs in this order: discover dirty repos, surface loose ends (task list state, abandoned threads from re-reading the session, new TODO/FIXME lines in diffs — printed once, no persistence), propose memory and skill writes inline, suggest a workshop-ingest if the session produced something generalisable, then per-repo verify-commit-push with confirmation at every step.

Each repo gets a generated commit message in my voice (lowercase, prefix-tagged) which I can edit before applying. Push is a separate confirmation. Push failure marks the repo “committed locally only” and continues. Re-running /clinch resumes naturally because the whole thing is stateless — it just finds whatever is still dirty.

The SessionEnd hook is a small bash script in bin/clinch-nudge.sh registered in settings.json. Same glob, prints a single line to stderr if any repo is dirty, exits.

The first run

After building it I ran /clinch to commit Clinch itself. It found three dirty repos: claude-config (the work), mission_control (stale doc archives from a previous session), and harbor-app (Vercel CLI artifacts I hadn’t gitignored). It committed and pushed the first two. It refused harbor-app — those auth.json and config.json files look user-specific and probably want a .gitignore entry, which is a deliberate decision I should make, not something Clinch should bury in a commit.

I’d built it to clean dirt and it correctly chose not to.