/handoff
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`.
Claude Code
$ npx -y skills add wenlan-app/wenlan --skill handoff --agent claude-code
Codex
$ npx skills add wenlan-app/wenlan --skill handoff -a codex -y
Cursor
$ npx skills add wenlan-app/wenlan --skill handoff -a cursor -y
Gemini CLI
$ npx skills add wenlan-app/wenlan --skill handoff -a gemini-cli -y
GitHub Copilot
$ npx skills add wenlan-app/wenlan --skill handoff -a github-copilot -y
OpenCode
$ npx skills add wenlan-app/wenlan --skill handoff -a opencode -y
Windsurf
$ npx skills add wenlan-app/wenlan --skill handoff -a windsurf -y
SKILL.md
handoff.SKILL.mdname: 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__wenlan__update_brief", "mcp__wenlan__list_pages", "mcp__wenlan__read_page", "mcp__wenlan__write_page", "mcp__wenlan__page_basis", "mcp__wenlan__page_code_basis"]
user-invocable: true
/handoff
Close the session with three separate artifacts:
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/`.
It also brings the wiki pages this session used up to date (step 7).
Run `echo $CODEX_THREAD_ID` once; when it is non-empty, pass `session: "codex:<that id>"` on `capture`, `write_page` and `update_brief`.
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
handoff_arg="<the Space name passed to /handoff, empty when none>"
# The resolver ships inside the installed plugin; the relative path only
# exists in a wenlan checkout.
resolver="$(find "$HOME/.codex/plugins/cache" -path '*/wenlan/*/bin/resolve-space.sh' 2>/dev/null | head -1)"
resolved="$("${resolver:-plugin-codex/bin/resolve-space.sh}" --cwd "$PWD" --arg "$handoff_arg" --new-repo-fallback 2>/dev/null)"
space="$(printf '%s\n' "$resolved" | cut -f1)"
source_layer="$(printf '%s\n' "$resolved" | cut -f2)"If the user passed a Space name (`/handoff <space>`), pass it as `--arg <space>` to resolve-space.sh.
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.
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. Outside a Git repository, a pin, explicit argument, default, or mapping still resolves a Space, and the Brief update and captures still run.
2. Read the Brief before composing deltas
W="$(command -v wenlan || echo "$HOME/.wenlan/bin/wenlan")"
brief_before=""
daemon_down=0
if [ -n "$space" ]; then
"$W" --format json status >/dev/null 2>&1 || daemon_down=1
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
daemon_down=0
brief_before="$("$W" --format json --space "$space" brief)"
source_layer="cwd-repo"
elif [ "$space_probe" = "Error: space '$space' not found" ]; then
: # absent Space: the typed update creates it
elif [ "$daemon_down" = 1 ]; then
brief_before=""
echo "Wenlan is not running; this handoff will be saved locally and sync when it starts"
else
printf "%s\n" "$space_probe" >&2
exit "$space_probe_status"
fi
else
brief_status=0
brief_output="$("$W" --format json --space "$space" brief 2>&1)" || brief_status=$?
if [ "$brief_status" -eq 0 ]; then
daemon_down=0
brief_before="$brief_output"
elif [ "$daemon_down" = 1 ]; then
brief_before=""
echo "Wenlan is not running; this handoff will be saved locally and sync when it starts"
else
printf "%s\n" "$brief_output" >&2
exit "$brief_status"
fi
fi
fiRead 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.
`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.
3. Preview pending captures and gather evidence
Best-effort; skip silently when `daemon_down=1` or the command fails:
"$W" --format json --space "$space" memories --pending -l 50
Filter by `created_at >= last_handoff_at`, or 12 hours ago when absent. Show at most three when any match, then continue automatically; `$wenlan curate captures` remains opt-in.
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.
4. Write the session log
Write `~/.wenlan/sessions/<YYYY-MM-DD-HHmm>-<slug>.md` with Accomplished, Decisions, Lessons & Gotchas, Open Threads, Captures stored, Pages touched, and Git summary. Pages touched lists each page this session used by title with the planned action; step 7 fills in the outcome. This is narrative history, not current-work authority. It is a plain file and must never depend on the daemon, so write it before the Brief update.
5. Build and apply one typed Brief update
Compare the session outcome with `brief_before` and write one `BriefUpdateRequest` JSON file:
{
"space": "<resolved Space>",
"caller_id": "codex",
"operation_id": "<unique id retained for retries of this handoff>",
"summary": {
"text": "<concise last-session summary>",
"expected_version"Read more
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__wenlan__update_brief", "mcp__wenlan__list_pages", "mcp__wenlan__read_page", "mcp__wenlan__write_page", "mcp__wenlan__page_basis", "mcp__wenlan__page_code_basis"] user-invocable: true
/handoff
Close the session with three separate artifacts:
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/`.
It also brings the wiki pages this session used up to date (step 7).
Run `echo $CODEX_THREAD_ID` once; when it is non-empty, pass `session: "codex:<that id>"` on `capture`, `write_page` and `update_brief`.
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
handoff_arg="<the Space name passed to /handoff, empty when none>"
# The resolver ships inside the installed plugin; the relative path only
# exists in a wenlan checkout.
resolver="$(find "$HOME/.codex/plugins/cache" -path '*/wenlan/*/bin/resolve-space.sh' 2>/dev/null | head -1)"
resolved="$("${resolver:-plugin-codex/bin/resolve-space.sh}" --cwd "$PWD" --arg "$handoff_arg" --new-repo-fallback 2>/dev/null)"
space="$(printf '%s\n' "$resolved" | cut -f1)"
source_layer="$(printf '%s\n' "$resolved" | cut -f2)"If the user passed a Space name (`/handoff <space>`), pass it as `--arg <space>` to resolve-space.sh.
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.
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. Outside a Git repository, a pin, explicit argument, default, or mapping still resolves a Space, and the Brief update and captures still run.
2. Read the Brief before composing deltas
W="$(command -v wenlan || echo "$HOME/.wenlan/bin/wenlan")"
brief_before=""
daemon_down=0
if [ -n "$space" ]; then
"$W" --format json status >/dev/null 2>&1 || daemon_down=1
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
daemon_down=0
brief_before="$("$W" --format json --space "$space" brief)"
source_layer="cwd-repo"
elif [ "$space_probe" = "Error: space '$space' not found" ]; then
: # absent Space: the typed update creates it
elif [ "$daemon_down" = 1 ]; then
brief_before=""
echo "Wenlan is not running; this handoff will be saved locally and sync when it starts"
else
printf "%s\n" "$space_probe" >&2
exit "$space_probe_status"
fi
else
brief_status=0
brief_output="$("$W" --format json --space "$space" brief 2>&1)" || brief_status=$?
if [ "$brief_status" -eq 0 ]; then
daemon_down=0
brief_before="$brief_output"
elif [ "$daemon_down" = 1 ]; then
brief_before=""
echo "Wenlan is not running; this handoff will be saved locally and sync when it starts"
else
printf "%s\n" "$brief_output" >&2
exit "$brief_status"
fi
fi
fiRead 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.
`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.
3. Preview pending captures and gather evidence
Best-effort; skip silently when `daemon_down=1` or the command fails:
"$W" --format json --space "$space" memories --pending -l 50
Filter by `created_at >= last_handoff_at`, or 12 hours ago when absent. Show at most three when any match, then continue automatically; `$wenlan curate captures` remains opt-in.
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.
4. Write the session log
Write `~/.wenlan/sessions/<YYYY-MM-DD-HHmm>-<slug>.md` with Accomplished, Decisions, Lessons & Gotchas, Open Threads, Captures stored, Pages touched, and Git summary. Pages touched lists each page this session used by title with the planned action; step 7 fills in the outcome. This is narrative history, not current-work authority. It is a plain file and must never depend on the daemon, so write it before the Brief update.
5. Build and apply one typed Brief update
Compare the session outcome with `brief_before` and write one `BriefUpdateRequest` JSON file:
{
"space": "<resolved Space>",
"caller_id": "codex",
"operation_id": "<unique id retained for retries of this handoff>",
"summary": {
"text": "<concise last-session summary>",
"expected_version"Open-source Obsidian alternative that works with your existing vault. The knowledge base you don't have to maintain: your AI tools keep it organized and up to date, with no API keys or plugins to set up. For you and your team.
Other skills on wenlan.
More skills from other plugins.
codebase-wiki
How to work in a Codebase Wiki project (the `codebase-wiki` starter pack): an agent-authored, source-grounded wiki of the…
academic-paper-reviewe…
Simulates academic peer review, evaluating papers across Originality, Methodology, Results, and Writing to provide Major/Minor…
Questions about handoff.
- Which coding agents can use handoff?
- handoff installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.

