handoff ยท diff
git:20260728.1178e18 to git:20260728.82b63a0
111 added, 72 removed. Audit A to A.
---
name: handoff
description: >
End a Codex 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__wenlan__capture", "mcp__wenlan__list_pending"]
user-invocable: true
---
# /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="$(plugin-codex/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:
+ ## 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 the Brief
- version plus every item's exact ID, version, state, text, added date, and gate.
- Use `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__wenlan__list_pending(limit=50)
+ 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
```
- Filter by `created_at >= last_handoff_at`; use 12 hours ago when absent. If
- none match, say nothing. Otherwise show at most three and proceed
- automatically. `/curate captures` remains opt-in.
-
- ## 4. Gather evidence and capture durable knowledge
-
- For a git repository, inspect recent log, short status, a bounded diff stat,
- and worktree list. Combine them with the conversation.
-
- Store one atomic durable item per call:
+ 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__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.
- Skip transient state and facts recoverable from git. 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__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 is narrative history, not 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 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": "codex",
"operation_id": "<unique id retained for retries of this handoff>",
"summary": {
"text": "<concise last-session summary>",
"expected_version": 0
},
"mutations": []
}
```
Use the existing Brief version instead of `0` when present.
+ If `space` is empty, skip this typed update entirely.
- - `add`: genuinely new open work, state `active` or `backlog`, optional gate.
- - `edit`, `move`, `set_gate`, `complete`: exact existing `item_id` and read
- `expected_version`.
- - Completion removes the item; there is no Done state.
- - Never fuzzy-match. If identity is ambiguous, leave the existing item
- 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 once. Interpret
- `applied`, `conflicts`, `projection_path`, and `warnings` independently.
- Non-overlapping changes may commit while a stale same-item change conflicts.
- Never resolve a conflict by guessing; re-read the Brief first.
+ 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.
- ## 8. Snapshot and report
+ 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.
- Best-effort commit the logical `~/.wenlan/` file batch at the session boundary;
- do not fail if no repository is configured or a commit races.
+ ## 5. Store durable captures
- Report capture counts, session-log path, applied/conflicted Brief deltas,
- Brief version, and projection path or warning. The Markdown projection is an
- inspectable receipt, never the authority.
+ For each drafted durable item, call:
+
+ ```text
+ mcp__wenlan__capture(
+ content="<self-contained statement with why>",
+ memory_type="<decision|lesson|gotcha|preference|fact>",
+ space="<resolved Space>"
+ )
+ ```
+
+ 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.