Skip to content
Documentation
Skill

/handoff

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.

From plugin
wenlan
6415 skills3 agents1 MCP
Install
$ npx -y skills add 7xuanlu/wenlan --skill handoff --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/handoff

Context preview

The summary Claude sees to decide when to auto-load this skill.

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.

SKILL.md

handoff.SKILL.md
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"]
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/`.

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 (`/wenlan: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=""
brief_absent=0
daemon_down=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
    elif printf '%s' "$space_probe" | grep -qE 'tcp connect error|daemon not reachable'; then
      daemon_down=1
      brief_before=""
      echo "wenlan daemon unreachable — this handoff will queue its writes"
    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
      brief_before="$brief_output"
    elif printf '%s' "$brief_output" | grep -qE 'tcp connect error|daemon not reachable'; then
      daemon_down=1
      brief_before=""
      echo "wenlan daemon unreachable — this handoff will queue its writes"
    else
      printf "%s\n" "$brief_output" >&2
      exit "$brief_status"
    fi
  fi
fi

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.

`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; `/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, and Git summary. 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.

Best-effort commit the logical `~/.wenlan/` file batch; do not fail if no repository is configured or a commit races.

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": 0
  },
  "mutations": []
}

Use the existing Brief version instead of `0` when present. When `daemon_down=1`, use `expected_version: 0` — the daemon reconciles the summary version when it replays the queued file — and author only `add` mutations; do not author `edit`, `move`, `set_gate`, or `complete` without a Brief snapshot. If `space` is empty, skip this typed update en

Read more
Ships withwenlan

Wenlan is a knowledge base for the AI-native age. Your AI agents capture what they learn, Wenlan keeps it current and distills it into source-cited wiki pages you can trust

Get the whole plugin

Other skills on wenlan.

prove
Skill

prove

Per-surface verification loops for wenlan — daemon, cli, mcp, plugin, suite strength (mutation), behavior trace, weekly sweep. Routes to scripts; every check…

@7xuanlu@7xuanluView Skill
verify
Skill

verify

Drive/evidence recipe for verifying wenlan changes at their real surfaces (daemon HTTP, CLI, MCP stdio). The handle file the built-in verify protocol expects;…

@7xuanlu@7xuanluView Skill
brief
Skill

brief

Read the current Space-owned project Brief from Wenlan for Codex. With an optional topic, appends separately labeled related context from the same Space.…

@7xuanlu@7xuanluView Skill
capture
Skill

capture

Save a durable memory to Wenlan from Codex. Use proactively when the user states a preference, makes a decision, corrects you, or shares a durable fact.…

@7xuanlu@7xuanluView Skill