handoff ยท diff

git:20260728.1178e18 to git:20260728.82b63a0

112 added, 95 removed. Audit A to A.

---
name: handoff
description: >
End a work session. Stores durable captures, writes a narrative session log,
and automatically applies typed item-level deltas to the current Space Brief.
Invoked as `/handoff`.
allowed-tools: ["Bash", "mcp__plugin_wenlan_wenlan__capture", "mcp__plugin_wenlan_wenlan__list_pending"]
---
# /handoff
- Close the current work session with three distinct artifacts:
+ Close the session with three separate artifacts:
- 1. Durable MCP captures in the daemon.
- 2. A chronological session log in `~/.wenlan/sessions/`.
- 3. A typed update to the Space-owned Brief.
+ 1. A typed update to the daemon-owned Space Brief.
+ 2. Durable MCP captures in that Space.
+ 3. A chronological session log in `~/.wenlan/sessions/`.
- The Brief in the daemon is the source of truth for current project state.
- `~/.wenlan/sessions/_status/<space>.md` is a one-way human receipt written by
- the daemon. Never read, edit, or overwrite that receipt as authority.
+ The daemon Brief is current-work authority. Its
+ `~/.wenlan/sessions/_status/<space>.md` projection is a one-way human receipt.
+ Never read, edit, or overwrite that receipt as authority.
## 1. Resolve repository and Space
```bash
repo="$(git -C "$PWD" rev-parse --show-toplevel 2>/dev/null || true)"
- if [ -n "$repo" ]; then project="$(basename "$repo")"; else project="$(basename "$PWD")"; fi
+ if [ -n "$repo" ]; then
+ common="$(git -C "$PWD" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true)"
+ case "$common" in
+ */.git) project="$(basename "$(dirname "$common")")" ;;
+ *) project="$(basename "$repo")" ;;
+ esac
+ else
+ project=""
+ fi
resolved="$("$CLAUDE_PLUGIN_ROOT/bin/resolve-space.sh" --cwd "$PWD" 2>/dev/null)"
space="$(printf '%s\n' "$resolved" | cut -f1)"
source_layer="$(printf '%s\n' "$resolved" | cut -f2)"
+ if [ -z "$space" ] && [ -n "$project" ]; then
+ space="$project"
+ source_layer="cwd-repo-new"
+ fi
```
- Print the resolution. If no Space resolves, continue with captures and the
- session log, but stop before the Brief update and report that precise gap.
- Do not guess a different Space.
+ Print `space` and `source_layer`. Explicit pins, defaults, and mappings still
+ win. `cwd-repo-new` is the approved first-handoff fallback: use the canonical
+ repository basename, which the user can override through normal Space config.
+ Do not invent any other Space name.
- ## 2. Read the Brief before composing deltas
+ Outside a Git repository, do not derive a new Space from the directory
+ basename. If resolution still leaves `space` empty, skip the Brief read and
+ typed update, do not issue Space-scoped captures, and continue with the
+ unscoped session log and any unscoped durable captures.
- When `space` is non-empty, run:
+ ## 2. Read the Brief before composing deltas
```bash
W="$(command -v wenlan || echo "$HOME/.wenlan/bin/wenlan")"
- brief_before="$("$W" --format json --space "$space" brief)"
- ```
-
- This read is mandatory before any Brief delta is authored. Retain:
-
- - Brief `version` for the summary CAS.
- - Every active/backlog item `id`, `version`, `state`, `text`, `added_at`, and
- optional `gate`.
- - `last_handoff_at` for the pending-capture window.
-
- `brief_not_created` is valid: use summary `expected_version: 0`; the update may
- create the Space and Brief. Reads themselves never create state.
-
- ## 3. Preview recent pending captures
-
- Call:
-
- ```text
- mcp__plugin_wenlan_wenlan__list_pending(limit=50)
- ```
-
- Filter by `created_at >= last_handoff_at`. If the Brief has no
- `last_handoff_at`, use 12 hours ago. If none match, say nothing. Otherwise show
- at most three and proceed automatically; `/curate captures` remains opt-in.
-
- ## 4. Gather evidence and infer durable captures
-
- For a git repository, inspect:
-
- ```bash
- git -C "$repo" log --oneline -20
- git -C "$repo" status --short
- git -C "$repo" diff --stat HEAD~5..HEAD 2>/dev/null || true
- git -C "$repo" worktree list
+ brief_before=""
+ brief_absent=0
+ if [ -n "$space" ]; then
+ if [ "$source_layer" = "cwd-repo-new" ]; then
+ space_probe_status=0
+ space_probe="$("$W" --format json spaces show "$space" 2>&1)" || space_probe_status=$?
+ if [ "$space_probe_status" -eq 0 ]; then
+ brief_before="$("$W" --format json --space "$space" brief)"
+ source_layer="cwd-repo"
+ elif [ "$space_probe" = "Error: space '$space' not found" ]; then
+ brief_absent=1
+ else
+ printf "%s\n" "$space_probe" >&2
+ exit "$space_probe_status"
+ fi
+ else
+ brief_before="$("$W" --format json --space "$space" brief)"
+ fi
+ fi
```
- Combine this with the conversation. Store only durable decisions, lessons,
- gotchas, corrections, and facts. Skip transient state and facts recoverable
- from git.
-
- For each durable item, call one atomic capture:
+ Read the Brief before composing deltas. This read is mandatory before any Brief
+ delta is authored for a registered Space. Retain the Brief version and every
+ item's exact ID, version, state, text, added date, and gate. Use
+ `last_handoff_at` for the pending-capture window.
- ```text
- mcp__plugin_wenlan_wenlan__capture(
- content="<self-contained statement with why>",
- memory_type="<decision|lesson|gotcha|preference|fact>",
- space="<resolved only when non-empty>"
- )
- ```
+ `brief_not_created` is valid and write-free. Use summary
+ `expected_version: 0`. For `cwd-repo-new`, prove the Space is absent with
+ `spaces show` before composing deltas. Accept only the exact CLI error
+ `Error: space '<name>' not found` as first-handoff absence; any other probe
+ failure stops the handoff. An absent Space cannot have a Brief or existing
+ items, so use `expected_version: 0` and author no existing-item mutations. The
+ typed update may then create the Space and Brief.
- Do not ask about ordinary captures. Pause only for a contradiction, critical
- incident, irreversible production action, or genuine durability ambiguity.
+ ## 3. Preview pending captures and gather evidence
- ## 5. Write the chronological session log
+ Call `mcp__plugin_wenlan_wenlan__list_pending(limit=50)`. Filter by
+ `created_at >= last_handoff_at`, or 12 hours ago when absent. Show at most three
+ when any match, then continue automatically; `/curate captures` remains opt-in.
- Write `~/.wenlan/sessions/<YYYY-MM-DD-HHmm>-<slug>.md` with Accomplished,
- Decisions, Lessons & Gotchas, Open Threads, Captures stored, and Git summary.
- This log is narrative history, not the current-work authority.
+ For a repository, inspect a bounded recent log, short status, diff stat, and
+ worktree list. Combine that evidence with the conversation. Draft atomic
+ captures only for durable decisions, lessons, gotchas, corrections,
+ preferences, and facts. Skip transient or git-recoverable state.
- ## 6. Build one typed Brief update
+ ## 4. Build and apply one typed Brief update
- Compare the session outcome with the Brief read in step 2. Create one
+ Compare the session outcome with `brief_before` and write one
`BriefUpdateRequest` JSON file:
```json
{
"space": "<resolved Space>",
"caller_id": "claude-code",
"operation_id": "<unique id retained for retries of this handoff>",
"summary": {
"text": "<concise last-session summary>",
"expected_version": 0
},
"mutations": []
}
```
- Use the read Brief version instead of `0` when the Brief already exists.
- Mutation rules:
+ Use the existing Brief version instead of `0` when present.
+ If `space` is empty, skip this typed update entirely.
- - `add`: a genuinely new open item; choose `active` or `backlog`, with optional
- gate. The daemon supplies the added date when omitted.
- - `edit`, `move`, `set_gate`, `complete`: use the exact existing `item_id` and
- its read `expected_version`.
- - Completed work uses `complete`; it does not become a hidden third state.
- - Never fuzzy-match an existing item. If identity is ambiguous, leave it
- unchanged and do not manufacture an edit or completion.
- - Never auto-demote an untouched Active item. Active/Backlog changes must come
- from actual session evidence.
- - Do not add an item that already exists unchanged.
+ - `add`: genuinely new open work, in `active` or `backlog`, with an optional
+ gate.
+ - `edit`, `move`, `set_gate`, and `complete`: use the exact existing item ID.
+ - Every delta for one existing item uses the same version from the pre-handoff Brief snapshot.
+ Do not chain versions generated by earlier deltas in the same request.
+ - `complete` removes the item; there is no Done state.
+ - Never fuzzy-match. Leave an ambiguous item unchanged.
+ - Never auto-demote untouched Active work.
+ - Do not add an unchanged duplicate.
- ## 7. Apply automatically and inspect the receipt
+ Apply exactly once:
```bash
"$W" --format json --space "$space" brief update --file "$update_file"
```
- Do not ask for approval for this normal handoff update. Submit exactly once,
- then parse the typed receipt:
+ Do not ask approval for this normal handoff update. Interpret `applied`,
+ `conflicts`, `projection_path`, and `warnings` independently. Non-overlapping
+ changes may commit while a stale same-item delta conflicts. Re-read before any
+ safe mechanical reconciliation; never guess.
- - `applied` confirms item-level changes.
- - `conflicts` contains only stale summary/item versions or missing IDs.
- - `projection_path` identifies the human Markdown receipt.
- - `warnings` report projection failures without rolling back committed state.
+ Apply the Brief update before Space-scoped captures when this fallback is new.
+ That creates the basename Space through the typed handoff path without making a
+ read or a capture create state. If this first update fails, stop Space-scoped
+ captures and report the exact failure.
- Non-overlapping mutations may apply even when another mutation conflicts.
- Never retry a conflict by guessing. Re-read the Brief and report the exact
- conflicted item if a safe reconciliation is not mechanical.
+ ## 5. Store durable captures
- ## 8. Snapshot and report
+ For each drafted durable item, call:
- Best-effort commit the logical `~/.wenlan/` file batch at the session boundary;
- do not fail the handoff if no repository is configured or the commit races.
+ ```text
+ mcp__plugin_wenlan_wenlan__capture(
+ content="<self-contained statement with why>",
+ memory_type="<decision|lesson|gotcha|preference|fact>",
+ space="<resolved Space>"
+ )
+ ```
- Report capture counts, session-log path, applied/conflicted Brief deltas,
- Brief version, and projection path or warning. Do not claim the receipt is the
- authority; it is only the inspectable projection.
+ Use one atomic item per call. Do not ask about ordinary captures. Pause only
+ for a contradiction, critical incident, irreversible production action, or
+ genuine durability ambiguity.
+
+ ## 6. Write the session log and report
+
+ Write `~/.wenlan/sessions/<YYYY-MM-DD-HHmm>-<slug>.md` with Accomplished,
+ Decisions, Lessons & Gotchas, Open Threads, Captures stored, and Git summary.
+ This is narrative history, not current-work authority.
+
+ Best-effort commit the logical `~/.wenlan/` file batch; do not fail if no
+ repository is configured or a commit races. Report capture counts, session-log
+ path, applied/conflicted Brief deltas, Brief version, and projection path or
+ warning.