# Session 0016.0 — Transcript > App: dev-claude-plugin > Start: 2026-06-05T12-45 (PST) · End: 2026-06-05T17-45 (PST) > Type: coding > Goal: Auto-trigger (or offer) `wgl-session-finalize` when a `/goal` is achieved; persist a next-`/goal` to memory; explicit resume. > Outcome: Shipped plugin **0.15.0** — new `finalize-on-goal` Stop hook + the `/goal next` resume. Merged via PR #9 (`f406d8a`). ## Plan 1. Classify + open the session (coding) and claim the transcript ID. 2. Brainstorm the design (it has a real feasibility unknown). 3. Decide: trigger behavior (mode-governed), mechanism (one Stop hook), resume (explicit). 4. De-risk the load-bearing unknown — how a `/goal` achievement is detectable. 5. Implement: Stop hook + finalize-core policy + memory field + gate/init resume + version/docs. 6. Verify, branch→PR→merge (autonomous), finalize. ## Pre-session state Clean `main` at `70bf3e9`, source 0.14.0 (installed cache also 0.14.0 — operator had re-installed since the 0.13.0 era recorded in memory). No in-flight sessions. The plugin already had exactly one hook (the SessionStart session gate); `/goal` appeared in the skills only as a *string* the init/finalize skills emit for the operator to paste — the actual `/goal` command and its "Goal achieved" signal are harness-level. ## Turn-by-turn arc - **Gate + claim.** Classified the request as a coding session on the plugin itself, invoked `wgl-session-coding-init`, peeked (dry-run: nothing in flight) and claimed **0016**. Confirmed clean pushed `main`; noted source = cache = 0.14.0. - **Brainstorming.** Established the feasibility picture via the claude-code-guide agent: `/goal` is a real built-in that loops across turns and records an "achieved" entry on completion; there is **no GoalAchieved hook**; the `Stop` hook (every turn-end) and `UserPromptSubmit` (can block) are the levers; **hooks can't invoke a skill** — they inject context / block; **mode is not persisted** so a hook can't read yolo/careful. - **Decision 1 — trigger:** operator chose **mode-governed** (yolo → auto-finalize; careful → offer on next prompt). Since mode isn't readable by a hook, the hook is mode-blind and the *agent* branches. - **Decision 2 — mechanism:** operator chose **one Stop hook** (deterministic detect + sentinel + neutral nudge; agent branches; careful offer surfaces at goal-time then waits). - **Operator refinement on resume (#4):** resume-from-memory must be **explicit** — `/goal next` (gate) and `/wgl-session-coding-init next goal` (bookend) read a stored field; a normal init starts some other session; anything else → normal auto-detect. Honesty caveat recorded: bare `/goal` is the built-in's status command and may not be interceptable; `/goal next` is the dependable trigger. - **De-risking detection (the crux).** The goal-achieved format is undocumented and the Stop input carries no goal field; no `/goal` had ever been used locally to sample, and a loose regex would false-positive on prose (this very session discusses "goal_status"). Recovered the authoritative shape from the CLI **binary** (`~/.local/share/claude/versions/2.1.165`, Mach-O): goal events are `goal_status` **attachments**, **achieved = `met:true && !sentinel`** (the predicate the binary's own reverse-scan uses). Detection keys on the JSON *object structure* → prose-proof. - **Implementation.** Wrote `hooks/finalize-on-goal` (fail-open throughout; `grep` pre-gate; `resolve-app.py`; `--INPROGRESS` placeholder gate; sentinel count; block-reason nudge), registered it as a second `Stop` entry in `hooks.json`. Added the finalize-core "Entering finalize when a `/goal` completes" policy + Step 6 `**Next /goal:**` persistence; `publish-transcript.sh` sentinel cleanup; the gate's `/goal next` branch; coding-init Step 7a; version 0.15.0; CLAUDE.md/README. - **Verification.** Ephemeral harness (`/tmp/wgl-fog-test.sh`): genuine achievement among `met:false`/`sentinel`/prose decoys → count **1**; prose-only → **0**; full hook emits the block once, sentinel suppresses re-fire, prose-only and no-placeholder stay silent. `jq empty` (both JSON), `bash -n` (both scripts), no trailing inline CLI comments. - **Land.** Spec committed (`fc969a7`), implementation committed (`566c586`) on `feat/finalize-on-goal`; pushed; PR **#9** opened and **merged** (`f406d8a`) via the Gitea API (no gh/tea); branch deleted; local `main` fast-forwarded. ## Cut state (end of session) | Repo | Branch→main | Commits / PR | State | | --- | --- | --- | --- | | wiggleverse-dev-claude-plugin | `feat/finalize-on-goal` → `main` | design `fc969a7`, impl `566c586`, merge `f406d8a` (PR #9) | Merged, branch deleted, `main` clean & pushed | Source now **0.15.0**; installed cache still **0.14.0** (lags until re-install). No open PRs, no dirty tree, no unpushed commits. Deferred decisions: none (every call decided jointly via `AskUserQuestion`). ## What lands on the operator's plate - **Re-install** to make 0.15.0 live: `/plugin marketplace update` + `/plugin install`. The new Stop hook activates only on the **next new session**. - **Detection is best-effort / fail-open.** If a Claude Code upgrade changes the `goal_status` shape the hook silently stops nudging (degrades to manual finalize); re-confirm against a real `/goal` run or the CLI binary and update the `jq`. - Bare `/goal` resume is best-effort; `/goal next` is dependable. ## Prompt the operator can paste into the next session ``` /goal Re-install plugin 0.15.0, then verify finalize-on-goal end-to-end live: in a tracked session run a throwaway /goal that completes, confirm the Stop hook nudges wgl-session-finalize (yolo auto / careful offer), and confirm `/goal next` resumes the stored Next /goal from this repo's memory. ```