# /refocus — concept-bound session forking

> 📊 **Stakeholder deck**: <https://nginx.ai-servicers.com/presentations/refocus/>
> Regenerate when material changes (`/understandingdeck`).

**Status:** PROPOSAL v2.1 — review-board cycle 1 complete (Gemini, Codex, Claude review-board); user decisions locked; deck deployed; ready for skill build. v2.1 adds D5 + §8g (mandatory /context-save propagation at `/refocus-complete`).
**Authored by:** administrator-claude · 2026-04-26.
**Audience:** the user, future review-board passes, and the future session that builds this skill.
**v1 → v2 deltas:** see §12.

---

## 1. The problem

When a user works in Claude Code from a project directory (e.g. `~/projects/agents/memory`), conversations drift. A session that started about agent-memory ends up:

1. Designing a platform-wide MCP standard (lands in `~/projects/mcp/MCPSTANDARD.md`)
2. Writing a migration plan for code-executor (lands in `~/projects/mcp/code-executor/MIGRATION-TO-MCPSTANDARD.md`)
3. Designing a meta-skill for session management (this doc, landing in `~/.claude/skills/refocus/DESIGN.md`)

The **artifacts** end up in the right files. But the **session transcript** — the full reasoning history including dead ends, review-board cycles, design pivots, the *why* behind every decision — is mis-tagged: stored under `~/.claude/projects/-home-administrator-projects-agents-memory/<session>.jsonl`, indistinguishable from agent-memory work.

Three concrete losses from this:

- **Future-me** opening `~/projects/mcp/` for the first time gets the artifacts but not the reasoning that produced them. CLAUDE.md is summary-shaped; agent-memory is fact-shaped; neither is a transcript.
- **Future-me** opening `~/projects/agents/memory/` to resume agent-memory work has to wade through 50k tokens of MCP-standard tangents to find the agent-memory thread.
- **Cross-session learning** (improving the design over weeks) is degraded — when the question is "how did we land on the SSH-stdio dispatcher pattern?", the answer is in the wrong session's transcript.

**At enterprise scale** (multi-year ecosystem, thousands of project directories, possibly multi-machine and multi-team) this gets worse: every session bleeds context into wrong directories. The skill makes session boundaries match concept boundaries by design.

**Case study: this very session is the failure mode** — used as test data when vetting the brief format.

## 2. Goal & non-goals

**Goal:** make every directory in `~/projects/` (and `~/.claude/skills/`) accumulate a focused, deep, longitudinal session history specific to its concept. Future sessions inherit that history naturally just by `cd`-ing into the directory.

**Non-goals:**
- Replace `/compact` (which compresses the current session's transcript). `/refocus` *redirects* to a different session; `/compact` *trims* the current one.
- Replace agent-memory (which stores facts/decisions/preferences). `/refocus` handles transcript-shaped knowledge; agent-memory handles bullet-shaped knowledge.
- Replace the `Agent` (subagent) tool (which is for ephemeral, return-a-result workers). `/refocus` is for persistent, cwd-bound work that gets its own transcript history.
- Auto-detect and auto-fork drift. Detection is hard; auto-fork is wrong (cross-cutting work like the MCP-standard episode genuinely *needed* the agent-memory context to exist).

## 3. Foundational decisions (locked)

| # | Decision | v1 | Future |
|---|---|---|---|
| D1 | Trigger model | **Manual only** (`/refocus <path>`) | v2: manual + auto-suggest, gated on hooks producing 98%+ accurate, low-noise drift signals |
| D2 | Fork mechanism | **Manual relaunch with a pre-generated `--session-id`.** Skill writes brief, generates a UUIDv4 SID, embeds it in the brief, prints `cd <dest> && claude --session-id <SID>` for the user to run. Child's transcript lands at `~/.claude/projects/<encoded-dest-cwd>/<SID>.jsonl` — the cwd-bound location future sessions in `<dest>` discover via `claude --resume <SID>`. | Optional `--oneshot` mode that uses `claude --session-id <SID> -p "$(cat brief.md)"` as a Bash subprocess for non-interactive deliverables; subagent-as-fork stays **rejected** because subagent transcripts are stored under the parent's session directory, not under `<encoded-dest-cwd>`, breaking the "future-me at dest finds the history" property. |
| D3 | Handoff shape | **Visible, git-tracked, colocated.** All per-event files at `<dir>/docs/refocus/<id>.md`. **`<dir>/docs/refocus/INDEX.md` is gitignored** — auto-regenerated cache, never hand-edited; it's the only source of high-frequency churn, and segregating it absorbs all the git-noise concern reviewers raised. Per-event files have ≤4 status transitions in their lifetime — those commits are legitimate audit trail of architectural work, not noise. Hidden machine-local stores (`.claude/refocus/`) explicitly rejected: at enterprise scale they break cross-machine continuity and discoverability via standard tools (find, IDE, GitLab UI). | — |
| D4 | **Spawn-graph topology** (new in v2) | **Strict tree, single root per session.** Children are leaves: they receive a brief, run to completion against its Definition of Done, and return a Result. **Children NEVER call `/refocus` themselves** — if they discover work that belongs elsewhere, they surface it in `Result.suggested_follow_ups` for the parent to decide. Mirrors call-stack semantics. Eliminates loop and DAG complexity entirely, by construction. **Hard guardrail enforced by the skill** (not just a brief instruction): `/refocus` refuses to execute when invoked from a child session, with error: *"Architectural violation: Child sessions cannot fork. Surface this work in Result.suggested_follow_ups and return to parent via /refocus-complete."* | — |
| D5 | **Completion propagation** (new in v2.1) | **Three-layer trigger ensuring material work surfaces beyond the conversation.** (1) **Cognitive** — `/refocus-complete` requires the child to enumerate `Result.material_changes` (or mark N/A) before flipping status. Forces the explicit thought "what at the conceptual level changed?" (2) **Mechanical** — `/refocus-complete` invokes `/context-save` as its penultimate step, promoting material decisions into `<dest>/docs/context/*` so future sessions auto-load the canonical state. (3) **Belt-and-suspenders** — a SessionEnd hook reading `SESSION_REFOCUS_ROLE=child` detects abandonment (child exits without `/refocus-complete`), emits a warning, and invokes `/context-save` anyway. See §8g. | — |

## 4. File layout

### 4a. Per-directory tree

Every project directory that participates gets a `docs/refocus/` subdirectory. Created lazily on first use.

```
<project-dir>/
├── .gitignore                                   ← contains "docs/refocus/INDEX.md"
└── docs/
    └── refocus/
        ├── INDEX.md                             ← gitignored auto-regenerated cache
        ├── 2026-04-26-mcp-standard-a3f91c.md    ← incoming brief + result (git-tracked)
        ├── 2026-04-27-deck-redesign-b21d40.md
        └── archive/                             ← optional GC bucket (see §4f)
            └── 2026-Q1/
                └── 2026-01-15-old-thing-c0ffee.md
```

### 4b. The id format

`<YYYY-MM-DD>-<slug>-<6hex>`

- `<YYYY-MM-DD>` — date of spawn (UTC). Chronological sort works on filename alone.
- `<slug>` — short kebab-case identifier the source session chose. Aim for 2-4 words.
- `<6hex>` — random 24-bit suffix from the `child_session_id` UUID. ~16M combinations; collision probability negligible at enterprise scale (thousands of dirs × hundreds of refocuses/dir over years). Kept for safety; collision recovery via `-2` suffix is uglier.

The 6hex is the **first 6 chars of the child_session_id UUID** — same key, different presentations. `grep -r a3f91c ~/projects` finds the file, the child's transcript at `~/.claude/projects/<encoded-dest-cwd>/a3f91c…<UUID>.jsonl`, and any cross-references in CLAUDE.md or chat in one shot.

### 4c. The destination file

`<dest>/docs/refocus/<id>.md` — git-tracked, the canonical record.

```yaml
---
id: 2026-04-26-mcp-standard-a3f91c
status: reserved              # reserved | brief | in-progress | result | blocked | abandoned
child_session_id: a3f91c2e-7b8d-4e5f-9a1b-c2d3e4f5a6b7
spawn_mode: manual            # manual | oneshot
spawned_at: 2026-04-26T19:23:00Z
launched_at: null             # set when child first opens via claude --session-id
completed_at: null            # set when child writes Result
source_dir: /home/administrator/projects/agents/memory
source_session_id: <parent-jsonl-id>
dest_dir: /home/administrator/projects/mcp
slug: mcp-standard
parent_refocus_id: null       # set if this refocus chain has predecessors
related_refocus_ids: []       # cross-links to sibling refocuses if any
done_when:                    # success criteria — child uses these as DoD
  - "MCPSTANDARD.md exists at ~/projects/mcp/ with §3-§9 sections complete"
  - "Review-board v3 cycle integrated"
out_of_scope:                 # things the child must NOT do
  - "Migrate code-executor to the standard (separate refocus)"
  - "Touch agent-memory work"
related:                      # external references
  - "/home/administrator/.claude/CLAUDE.md#engagement-style"
  - "GitLab issue or design doc URLs if any"
---

# Brief: MCP platform standard

## Why this branch exists
<one short paragraph — what triggered the spawn.>

## Inherited context
<5–15 bullets of load-bearing facts/decisions from the source session that
affect destination work. Curated, not transcript-dumped. Each bullet a
reusable fact.>

## Open questions / desired deliverables
<bullet list of what the child session is supposed to produce.>

## Hard rule for child
- Children are leaves. If you discover work that belongs in a different
  directory, do NOT call /refocus. Surface it in Result.suggested_follow_ups
  for the parent to decide.

## Pointer back
- Source session: `~/.claude/projects/<encoded-source-cwd>/<source-session-id>.jsonl`
- To continue this child later: `cd <dest_dir> && claude --resume <child_session_id>`

---

## Result
<empty until child writes>

<!--
When the child completes, it appends here:

### Status
- completed       # met all done_when criteria
- blocked         # hit a blocker requiring work in another directory; parent must orchestrate

### Definition-of-Done met
<checklist matching done_when from frontmatter, each item checked or noted as not met>

### Summary
<one paragraph: what was accomplished or where it blocked>

### Artifacts produced
- `<path>` — `<one-line description>`

### Suggested follow-ups (parent decides)
<bullets of "I noticed work belongs at <dir>" items the child surfaced for
parent to orchestrate. Each entry: dir, slug, one-line reason. Parent reads
and decides whether to spawn a sibling /refocus.>

### Material changes (for /context-save)
<list of decisions, contracts, or architecture changes that should be
promoted into <dest>/docs/context/* as canonical state. Each entry: which
context file (architecture | interfaces | conventions | gotchas | …) and
the one-line summary. Or: "N/A — investigation only, no canonical state
changed." This field is mandatory; child must enumerate explicitly before
status flips. /refocus-complete invokes /context-save immediately after
appending Result to promote these into the destination's docs/context/.>

### Child session
- Session jsonl: `~/.claude/projects/<encoded-dest-cwd>/<child_session_id>.jsonl`
- Completed at: <ISO ts>
-->
```

Status transitions:
- `reserved` → set on `/refocus` execution; SID is reserved but child hasn't launched.
- `brief` → set when source's `/refocus-complete` writes its outbound side. (Same as reserved at v1 — kept distinct for future tracking of the "reserved but never launched" garbage state.)
- `in-progress` → set when child first opens via `claude --session-id` and the auto-discovery hook flips status.
- `result` → set when child runs `/refocus-complete` and appends Result.
- `blocked` → set when child hits a blocker requiring orchestration; parent re-reads Result, spawns clearing children, then re-spawns or absorbs.
- `abandoned` → preserves brief as historical record; user-edited frontmatter with a `reason:` field.

### 4d. The source side — INDEX.md only, no separate outbound file

In v1 we proposed an `<id>.outbound.md` pointer at the source. Reviewers pointed out it duplicates information already captured in the source's `INDEX.md` row. **Dropped in v2.**

The source's record of the spawn is:
- A row in `<src>/docs/refocus/INDEX.md` (gitignored regen).
- A one-line marker in the source session's transcript: *"SPAWNED <id> → <dest_dir> (child_session_id: <UUID>). Awaiting result."* Lets cross-session search find the fork point even after INDEX.md regenerates.
- The destination file is the canonical record; source resume reads `<dest>/docs/refocus/<id>.md` directly when checking on a refocus's progress.

### 4e. The auto-maintained INDEX.md

`<dir>/docs/refocus/INDEX.md` — **gitignored**. Regenerated whenever the skill touches the directory.

```markdown
# Refocus index — <project-name>

(auto-generated; see docs/refocus/*.md for canonical state)

## Active (status ∈ {reserved, brief, in-progress, blocked})

| Date | Slug | Direction | Status | Counterpart |
|---|---|---|---|---|
| 2026-04-26 | mcp-standard | incoming | in-progress | from `~/projects/agents/memory` |
| 2026-04-28 | some-spawn | outgoing | reserved | to `~/projects/foo` |

## Recent (status=result, last 30 days)

| Date | Slug | Direction | Completed | File |
|---|---|---|---|---|
| 2026-04-15 | older-thing | incoming | 2026-04-18 | [open](2026-04-15-older-thing-aabbcc.md) |

## Archived

See `docs/refocus/archive/YYYY-QN/` for older entries; INDEX surfaces only the most recent 30 days.
```

The skill regenerates INDEX.md on every action. CLAUDE.md in the same project links to INDEX.md (skill auto-prepends the link on first use).

### 4f. GC / archival

After a per-event file has been at `status=result` for >90 days, the skill moves it to `<dir>/docs/refocus/archive/YYYY-QN/`. INDEX.md surfaces only live entries + last 30 days of completed; everything older requires `find docs/refocus/archive -name <id>.md`.

This keeps INDEX.md scannable at enterprise scale (a long-lived dir might accumulate hundreds of refocuses over years).

## 5. Brief schema — what's load-bearing

Required (frontmatter):

- `id`, `child_session_id`, `spawn_mode`, `status`, `spawned_at`, `source_dir`, `source_session_id`, `dest_dir`, `slug`, `done_when`, `out_of_scope`.
- `parent_refocus_id`, `related_refocus_ids`, `related` — empty if not applicable.

Required (body):

- **Why this branch exists** (1 paragraph) — the trigger.
- **Inherited context** (5–15 bullets) — load-bearing facts from source that affect destination work. Bullets, not prose. Each bullet a reusable fact.
- **Open questions / desired deliverables** — what the child must produce.
- **Hard rule for child** (boilerplate) — "you are a leaf, surface follow-ups, don't fork."
- **Pointer back** — source jsonl and child resume command.

Curation principle: **the brief is what the child needs to make good decisions about destination work**, written by the source's Claude based on its full context, capped to what's relevant. Anything that's "nice to know" goes via the source-jsonl pointer, not in the brief.

What's NOT in the brief:
- Full transcript dumps.
- Code excerpts (refer by path).
- Reviewer-by-reviewer feedback (cite the integration point, not the back-and-forth).

## 6. The drift rubric — when to refocus

Two firing conditions, both required:

1. **Subtree mismatch.** Work being done would create or modify files in a different `~/projects/<X>/` subtree than the current cwd.
2. **Independent resumption test** (Codex's framing — sharper than "multi-session lifespan"): *"If work stopped now, would the next session naturally start in `dest` rather than `src`?"* If yes, the work earns its own session at `<dest>`. If no, finish it here.

Optional helper signals (any one tightens the call but isn't required):
- Estimated work > 30 min
- Source session is already > 40% context (instinct mirrors `/compact`)
- > 1 artifact will be produced in the destination subtree

**Negative tests** — when NOT to refocus:
- Quick lookup or debug — one-off, returns to current work.
- Cross-cutting work that genuinely *needs* the source-session context to be done well (the MCP-standard episode is the canonical example).
- Tangent < 30 minutes with no artifacts.
- Reading something from another project to inform current work (use the file directly).
- **Work that needs the source's full transcript to reason** (e.g., three review-board cycles deep on a design where the child won't make sense without the rejection history). Refocus loses information here.

**Edge case — multiple drifts in one session.** A parent session can fan out N children sequentially or in parallel; under the strict-tree topology of D4 there is no DAG complexity. Reference earlier siblings via `related_refocus_ids` so the chain is traversable.

## 7. The skill's command surface

**Two slash commands. Everything else is auto-discovery on session start.**

- `/refocus <dest-dir> [--slug <s>] [--reason <r>] [--oneshot]` — at the **source** session. Skill:
  1. **Guard:** refuse if invoked from a child session (D4). Detect via `SESSION_REFOCUS_ROLE=child` env var set by SessionStart hook (§8a) when a session was launched via a refocus brief.
  2. Drafts brief + DoD + out-of-scope from context; asks user to confirm/expand each section.
  3. Generates `child_session_id` (UUIDv4); derives `id` (date+slug+6hex from UUID).
  4. Writes `<dest>/docs/refocus/<id>.md` (status=reserved).
  5. Regenerates source and dest INDEX.md.
  6. Writes a one-line transcript marker in source: *"SPAWNED <id> → <dest_dir>."*
  7. Prints the relaunch command:
     - Default (manual): `cd <dest> && claude --session-id <SID>` — interactive from start.
     - With `--oneshot`: `cd <dest> && claude --session-id <SID> -p "$(cat <dest>/docs/refocus/<id>.md)"` — non-interactive deliverable, source captures stdout when run from Bash. Note: `claude -p` sessions don't appear in the `--resume` picker by default; future resumption requires explicit `claude --resume <SID>`.

- `/refocus-complete` — at the **destination** session, when work is done. Skill:
  1. Prompts for Result content: Status (completed | blocked), DoD checklist, summary, artifacts, suggested_follow_ups, **and `material_changes` (D5 — mandatory enumeration; child must list canonical-state changes for `<dest>/docs/context/*` or explicitly mark N/A).**
  2. Appends Result to `<id>.md`, sets status=result (or =blocked if Status=blocked), completed_at.
  3. **Invokes `/context-save` for `<dest>`** (D5 mechanical layer) to promote material_changes into `docs/context/*`. Errors are surfaced but do not block status flip — child reports cleanly even on context-save failure; operator reviews after.
  4. Regenerates dest's INDEX.md.
  5. **Source-side reconciliation** is auto-discovery (§7 below): when source resumes, it reads its own outgoing INDEX rows, checks each dest file for status=result|blocked, surfaces results to the user.

**Auto-behaviors driven by SessionStart hook (§8a) — no slash command needed:**

- **Destination auto-resume.** When a session opens at a directory with INDEX.md showing one or more `status=brief|reserved` incoming briefs targeted at this `child_session_id`, the assistant's first message: *"This session is the child of refocus `<id>`. Load brief? [Y/n]"*. On yes, brief content is consumed as initial context, status flips to `in-progress`, `launched_at` is stamped.
- **Source auto-receive.** When a session resumes at a directory with outgoing INDEX rows whose dest files are now at status=result|blocked and not yet reconciled, the assistant's first message: *"The refocus you spawned to `~/projects/mcp` returned a result. Read it? [Y/n]"*. On yes, dest's Result section is loaded into context.

**Abandonment** is a single file edit. Set `status: abandoned`, add `reason:`. Rare enough not to deserve a command.

## 8. Integration points

### 8a. SessionStart hook — the substrate for auto-discovery
v1 hand-waved auto-discovery. v2 grounds it in a concrete mechanism: a Claude Code SessionStart hook (configurable in `~/.claude/settings.json`) runs the refocus auto-discovery script on every session open.

The script:
1. Walks up from cwd looking for the nearest `docs/refocus/INDEX.md` (or regenerates it from `*.md` if missing).
2. Sets env var `SESSION_REFOCUS_ROLE=child` if the current session id matches an incoming brief's `child_session_id`. The skill's `/refocus` guard reads this env to enforce D4.
3. Surfaces pending incoming briefs and pending result-receives as a system-reminder-style first-message prompt.

Hook implementation detail: the SessionStart hook sees `$CLAUDE_SESSION_ID` and `$CLAUDE_PROJECT_DIR` in env; the script can do everything it needs from those.

### 8b. CLAUDE.md
On first refocus into a directory, skill checks if that directory's `CLAUDE.md` references `docs/refocus/INDEX.md`. If not, prepends a 1-line block:

```markdown
> 🔀 **Session history (refocus)**: See [docs/refocus/INDEX.md](docs/refocus/INDEX.md) for incoming briefs and outbound spawns.
```

(Mirrors the pattern `/understandingdeck` uses.) Keeps directory-startup context-loading aware of refocus history.

### 8c. .gitignore
On first use of `docs/refocus/` in a project, the skill appends `docs/refocus/INDEX.md` to that project's `.gitignore` (creating the file if absent). One-time idempotent action.

### 8d. agent-memory (the MCP server at `~/projects/agents/memory`)

**Specifically:** this section is about the `agent-memory` MCP server (project at `~/projects/agents/memory`, exposing tools `mcp__agent-memory__write`, `mcp__agent-memory__recall`, `mcp__agent-memory__promote`, `mcp__agent-memory__resolve`, etc., scope-routed by cwd via `scope.default.yml`, postgres-backed once the daemon ships, with file-tier mirror at `~/.claude/projects/<encoded-cwd>/memory/`). Generic phrases like "agent memory" or "memories" are not what's meant here — this is the specific named system.

**Refocus does NOT write to agent-memory by default.** Briefs and Results are transcript-shaped reasoning and per-event audit records — neither is bullet-fact-shaped — and both are project-scoped. They belong in markdown at the destination directory (D3, §8g), not in a database routed through MCP.

**Test for the exception** — agent-memory is only the right home when *both* conditions hold:

1. The outcome is a **user-level preference, feedback rule, or cross-project pattern** — bullet-fact-shaped, not project-architecture-shaped.
2. It **cannot live in any project's `docs/context/*`** because it doesn't belong to a single project.

When the test passes, the skill offers a *single* opt-in `mcp__agent-memory__write` call as part of `/refocus-complete` (operator confirms per refocus; never automatic). When it fails — the common case — material decisions land in `<dest>/docs/context/*` via the chained `/context-save` (D5), not in agent-memory.

**Examples that PASS the test (rare):**
- *"User prefers `/refocus-complete` to print the resume command in chat as well as the brief"* — feedback-type, no project home.
- *"In this ecosystem, parents always re-spawn blocked work as a fresh refocus rather than absorbing it"* — cross-project pattern about how refocus is operated, not about any specific destination.

**Examples that FAIL the test (common — these belong in project files, not agent-memory):**
- *"refund-flow now uses two-phase commit"* → `~/projects/billing-service/refund-flow/docs/context/architecture.md`.
- *"code-executor uses socat-relay for SSH-piped stdio"* → `~/projects/mcp/code-executor/docs/context/architecture.md`.
- *"The MCP standard requires TLS day-one"* → `~/projects/mcp/MCPSTANDARD.md`.

**Why this constraint matters.** agent-memory's storage (`~/.claude/projects/<encoded-cwd>/memory/` file-tier; postgres for the daemon-tier) is hidden under `~/.claude/` and not git-tracked. Routing project-scoped refocus outputs through it re-introduces the cross-machine, IDE-invisible, no-grep problems D3 was designed to avoid. agent-memory is a tool for facts that *can't* live in a project file because they apply across projects; using it for project-scoped material would be the wrong tool, not just a stylistic choice.

### 8e. The `Agent` (subagent) tool
Subagents have a clean role in this design but are not the fork mechanism:
- **Subagent for brief drafting (optional in v1, recommended for v2):** source's Claude calls a subagent with "Read this conversation's last N turns + this list of files. Produce a curated brief for a session at <dest>. Output JSON matching the brief schema." Keeps source's context window from bloating with the brief-writing meta-task.
- **Subagent NOT used for forking.** Subagent transcripts are stored at `~/.claude/projects/<source-encoded-cwd>/<source-session-id>/subagents/agent-<id>.jsonl` — under the parent's session dir, not the encoded-dest-cwd location. This breaks the "future-me at dest finds the history" property in §1. Confirmed by Claude review-board's research; this is the structural reason subagent-as-fork is rejected even though `cwd` and persistence are supported.

### 8f. `--fork-session` and `--cwd`
v1 considered using `--fork-session` to inherit the source transcript blindly. **Rejected** — defeats the cleanup purpose. v2 always creates a fresh session at `<dest>` so destination accumulates clean concept-bound history.

If/when Anthropic ships native cwd-fork on the Agent tool (issue #12748) AND that variant stores transcripts at the encoded-dest-cwd location, `/refocus` may add an internal fast-path. Comment on #12748 added during this design cycle to lobby for the storage-location requirement.

### 8g. Integration with /context-save (D5 — completion propagation)

A `/refocus` work item produces three persistence layers at the destination, each populated by a distinct mechanism and serving a distinct role:

| Layer | Lives at | Populated by | Role |
|---|---|---|---|
| **Transcript** | `~/.claude/projects/<encoded-dest-cwd>/<SID>.jsonl` | Pre-generated `--session-id` (D2) | Full reasoning, every word; opt-in inheritance via `claude --resume <SID>` |
| **Per-event audit** | `<dest>/docs/refocus/<id>.md` (Brief + Result) | `/refocus` and `/refocus-complete` (D3) | Immutable record of what work happened, what changed, why |
| **Canonical state** | `<dest>/docs/context/*.md` (architecture, interfaces, conventions, gotchas, …) | `/context-save` (this section) | Current truth of the destination directory; auto-loaded by future sessions via CLAUDE.md |

The transcript answers *"what did we discuss?"*; the audit answers *"what work happened, what changed?"*; the canonical state answers *"what does this directory currently look like, for a session that's never seen it before?"*

**The pairing problem.** Per-event briefs are read intentionally (when investigating a specific past decision). The canonical state is read automatically (every new session at `<dest>` auto-loads CLAUDE.md → docs/context/*). If material work surfaces only in the brief and never propagates to docs/context/, future sessions won't know about it without explicitly hunting through history. The work is recorded but not *visible by default* — the audit equivalent of a closed Jira ticket nobody ever reads.

**The three-layer trigger** (D5):

1. **Cognitive — `material_changes` enumeration.**
   `/refocus-complete` requires the child to fill in the `Material changes (for /context-save)` field of the Result section: a list of decisions / contracts / architecture updates that should land in `docs/context/*`, or an explicit `N/A — investigation only`. The discipline is the *thought*, not the file write — many refocus events legitimately have nothing material (pure investigation, debugging, lookup) and N/A is the right answer there. Forcing the enumeration prevents quiet drop of material decisions.

2. **Mechanical — chained invocation.**
   After appending Result and flipping status, `/refocus-complete` invokes `/context-save` for `<dest>` deterministically. `/context-save` regenerates docs/context/* from the destination's current state (its existing job). The chain ensures material decisions land in canonical files at the moment the child considers itself done — no waiting for the next session, no relying on hooks firing reliably.

3. **Belt-and-suspenders — SessionEnd hook for abandonment.**
   If the child exits without running `/refocus-complete` (e.g. `/quit`, crash, lost connection), the SessionEnd hook reading `SESSION_REFOCUS_ROLE=child` (already set by §8a's SessionStart hook for D4) detects status≠result, emits a console warning *"Refocus child exiting without /refocus-complete — material work may not be surfaced"*, and invokes `/context-save` anyway so material reasoning embedded in the unfinished transcript still has a chance to land in canonical state.

**Why this isn't redundant with the user-level context-save SessionEnd hook:** the user-level hook fires unconditionally on every session exit (this is its existing job per its skill description). For non-refocus sessions that's exactly right. For refocus children, the layered triggers above make the *evaluation* explicit (cognitive) and the invocation deterministic at the right moment (mechanical, before the brief finalizes), instead of relying on a generic exit-time pass to catch everything. The user-level hook is the third backstop; D5 makes the first two explicit.

**Symmetric on the parent side.** When a parent receives a child's Result and decides next steps (ship, sibling-spawn, absorb), the parent's own decisions also produce material changes — covered by the parent session's normal `/context-save` SessionEnd hook firing on its eventual exit. Refocus doesn't need to do anything special on the parent end; the existing context-save substrate handles it.

**What `material_changes` looks like in practice:**

```
### Material changes (for /context-save)
- architecture.md — refund-flow now uses two-phase commit instead of saga
- interfaces.md — POST /refunds adds new x-idempotency-key header (required)
- gotchas.md — webhook retries can deliver out of order; consumer must dedupe
```

or:

```
### Material changes (for /context-save)
N/A — investigation only, root-caused #4421 to upstream library bug; no
canonical state changed at this directory. Filed upstream issue, linked
in suggested_follow_ups.
```

## 9. Edge cases & failure modes

- **Brief is too thin.** Child struggles. Mitigations: pointer-back includes source jsonl path so child can `Read` it directly if needed; schema enforces minimum bullet counts on Inherited Context; skill prompts source's Claude to confirm/expand each section before writing.
- **Brief is too thick.** Becomes a transcript dump, defeats the point. Mitigations: schema enforces sections; "Inherited context" must be bullets, capped at ~300 words; skill warns if exceeded.
- **Source session goes stale before child completes.** User spawns to dest, works there for a week, source jsonl auto-archived. Mitigations: dest file's "Inherited context" is self-contained; pointer-back to jsonl is a *bonus*, not a dependency.
- **Wrong destination.** User refocuses to `~/projects/foo` when it should have been `~/projects/bar`. Mitigations: edit `<id>.md` frontmatter to `status: abandoned` with a `reason:`. Run `/refocus <correct-dest>` again; new id, fresh start.
- **Child hits a blocker requiring work in another directory** (failure mode flagged by Gemini). Children cannot fork (D4). Procedure:
  1. Child runs `/refocus-complete` with `Status: blocked`.
  2. `Result.summary` describes the blocker.
  3. `Result.suggested_follow_ups` lists the work that needs to happen elsewhere to unblock.
  4. Source's auto-receive surfaces the blocked result.
  5. Parent decides: spawn one or more clearing children (siblings of the blocked one) to handle the follow-ups; once those return, parent re-spawns the blocked work as a fresh refocus, with `parent_refocus_id` chained to the original.
- **Race on simultaneous open.** Two terminal windows open the same brief at the same time. Both will get the auto-discovery prompt; skill warns on second resume (*"Brief was opened by another session at <ts>. Continue anyway? [y/N]"*). Not blocking — user might intentionally do so — but flagged.
- **User doesn't run the relaunch command.** Source continues, dest never opens, brief sits at status=reserved indefinitely. Mitigation: source's next `/refocus` checks for own outgoing briefs >24h at status=reserved, prompts: *"Pending refocus to <dest> still un-launched. Continue waiting, or abandon?"*
- **Destination doesn't exist or isn't a project dir.** Skill refuses with a clear error. Does NOT auto-create — operator must intentionally set up the project. (Caveat: the project-creation step is out of scope; refocus is for *existing* projects.)
- **Refocus chain too deep.** A parent fans out a child, gets a blocked result, fans out a clearing child, etc. Skill warns at chain depth > 5 — likely a design smell. Doesn't block.
- **Same-directory churn over years.** A long-lived project dir accumulates 500+ refocuses. INDEX.md becomes unreadable. Mitigation: GC moves anything >90 days at status=result to `archive/YYYY-QN/`. INDEX surfaces live + last 30 days only. Archive is grep-able offline.

## 10. What this is NOT

- **Not `/compact`.** `/compact` trims this session. `/refocus` redirects to a different session.
- **Not agent-memory.** Memory stores bullet-shaped facts. Refocus stores transcript-shaped reasoning. Complementary; one stores the *what*, the other stores the *how-we-got-here*.
- **Not the `Agent` (subagent) tool.** Subagents are ephemeral one-shot workers (transcript stored under parent's session dir). Refocus is for persistent, cwd-bound work.
- **Not `claude --fork-session` alone.** Fork copies history into the same cwd. Refocus curates a brief and binds it to a different cwd, with the destination's transcript stored at the encoded-dest-cwd location.
- **Not `/init`.** `/init` bootstraps a fresh project. Refocus assumes the project exists.
- **Not project management.** Briefs are not tickets. Use Linear/GitLab for ticketing; refocus is for concept-bound transcript routing.

## 11. v1 implementation surface

Skill files at `~/.claude/skills/refocus/`:

```
~/.claude/skills/refocus/
├── DESIGN.md                       ← this file
├── SKILL.md                        ← user-facing skill instructions
├── refocus.sh                      ← /refocus implementation
├── refocus-complete.sh             ← /refocus-complete implementation
├── session-start-hook.sh           ← installed in ~/.claude/settings.json
├── lib/
│   ├── brief-template.md
│   ├── index-regen.sh
│   ├── id-gen.sh                   ← UUIDv4 + slug → id
│   └── gc-archive.sh
└── presentation/
    └── refocus-presentation.html   ← /understandingdeck output
```

`SKILL.md` is the user-facing skill entry; this `DESIGN.md` is the architectural source of truth that the next session reads first when picking up the build.

## 12. v1 → v2 deltas (review-board cycle 1)

**Convergent across all three reviewers (integrated without dispute):**
- Pre-generated `child_session_id` embedded in brief (Claude rev-board's discovery; Codex made it explicit). Frontmatter elevated from "we'll figure it out" to first-class metadata.
- Drop `<id>.outbound.md` source-side file. INDEX.md row + transcript marker is sufficient (Claude rev-board, Codex).
- Reconcile §7 ↔ §11 to two commands (`/refocus`, `/refocus-complete`). Six-command list was leftover (Claude rev-board, Codex).
- Brief schema additions: `child_session_id`, `spawn_mode`, `done_when`, `out_of_scope`, `parent_refocus_id`, `related_refocus_ids`, `related` (Codex's framing).
- Drift rubric tightened to subtree-mismatch + independent-resumption-test (Codex's sharpest framing). Helper signals (>30 min, >40% context) added.
- Hard guardrail for child-cannot-fork — D4 in §3, enforced by SessionStart hook setting `SESSION_REFOCUS_ROLE=child` (Gemini's correct insistence on enforcement, not just brief instruction).
- Definition-of-Done distinguishes "completed successfully" vs "blocked, returning to parent" (Gemini's failure-mode catch); Result section adds Status field.
- Auto-discovery substrate grounded in SessionStart hook (Codex flagged underspec; v2 specifies the hook).
- Drop per-session-summary file proposal. `<id>.md` Result section is enough (Claude rev-board, Codex agree).

**User-locked decisions:**
- D3: visible `<dir>/docs/refocus/<id>.md` git-tracked, INDEX.md gitignored. Codex re-litigated on separation-of-concerns grounds; user's enterprise-scalability + multi-machine-continuity framing prevailed. Gemini conceded after re-challenge.
- D4: strict tree topology, children are leaves, `/refocus` refuses from child sessions. New in v2.
- Naming: `/refocus` retained. `/handoff` (Claude rev-board's pivot) rejected as implying ownership transfer to a remote agent.

**Reviewer recommendations NOT adopted (with reasoning):**
- Subagent-as-fork. Claude rev-board confirmed `cwd` and persistence work, but transcripts land under the parent's session dir, not the encoded-dest-cwd location. This breaks §1's third stated loss. **Pivot rejected; subagent stays as a brief-drafting helper only (§8e).**
- Bash-subprocess `claude --session-id -p` as primary fork mode. Claude rev-board pushed for it; rejected because `-p` is non-interactive (child can't prompt user mid-run) and `-p` sessions don't appear in `--resume` picker by default. Kept as `--oneshot` opt-in (§7).
- `.claude/refocus/` for transactional state. Codex re-raised after Gemini's concession; rejected on multi-machine-continuity grounds (gitignored = each machine has its own view of in-progress state, breaks cross-machine work).

**Anthropic upstream actions:**
- Comment posted on issue [#12748](https://github.com/anthropics/claude-code/issues/12748) requesting that any future cwd-on-Agent feature also store the subagent transcript at the encoded-dest-cwd location, not the parent's. This is the property that would let subagent-as-fork become viable.

## 13. Sequencing — what's next

1. ✅ DESIGN.md v2 written (this file).
2. → `/understandingdeck` for stakeholder/visual review.
3. → User reviews deck.
4. → Build `SKILL.md` + supporting scripts at `~/.claude/skills/refocus/`. Likely candidate: spawn the first real refocus from this session to `~/.claude/skills/refocus/` to dogfood the skill at construction time. (Subject to D4 — this session would be parent, build session would be child.)
5. → Dogfood: first production use is most likely the code-executor migration (`~/projects/mcp/code-executor/MIGRATION-TO-MCPSTANDARD.md` is already a refocus-shaped artifact written by hand from this session).
6. → Iterate on first-week experience; ship v1.1 with friction fixes.

## 14. Roadmap for enterprise use — NOT in v1

**Status:** Forward-looking only. **None of these change v2.1 decisions.** v1 ships single-developer; the items below become valuable at multi-engineer / multi-machine / on/offshore-24×7 scale, and are deferred until the friction is real. Captured here so that if/when scale issues appear, the upgrade path is already mapped.

The recurring tension at enterprise scale is: a brief is a *summary*, but post-mortems, audits, and engineer-handoff at 3 a.m. sometimes need the *full reasoning trail* — and the trail today lives in machine-local transcripts that no other engineer can see. The items below close that gap incrementally without breaking the v1 contract.

| # | Extension | What it solves | Fix surface |
|---|---|---|---|
| 1 | `assigned_to:` brief frontmatter field | 24×7 ownership tracking — who currently owns this refocus across shifts/timezones | Add to brief schema (§5); set in `/refocus`, cleared in `/refocus-complete` |
| 2 | Commit→refocus linkage | `git log --grep='refocus:<id>'` recovers every commit tied to a refocus, even after the agent session is gone | Optional `commit-msg` hook in child sessions prepending `[refocus:<id>]` |
| 3 | `alternatives_considered:` brief field | Postmortem question "did we consider X?" answerable without sharing transcripts | Brief schema addition; populated at `/refocus-complete` |
| 4 | `decision_rationale:` + `reviewer_pushback:` brief fields | Deeper audit trail when a decision is later questioned; preserves dissent that briefs currently flatten | Brief schema additions |
| 5 | Cross-dir global INDEX | "No central registry" friction at 100+ refocuses across many repos | Opt-in nightly cron generates `~/projects/REFOCUS-INDEX.md` from per-dir `INDEX.md` files |
| 6 | Opt-in transcript-to-repo commit | Full reasoning trail available to other engineers / auditors when needed | `/refocus-complete` prompts "Save full transcript? [y/N]" (default **NO**); on yes, copies child `<SID>.jsonl` to `<dest>/docs/refocus/transcripts/<id>.jsonl` and sets `transcript_saved: true` in brief frontmatter |
| 7 | `/scrub-transcript <path>` helper skill | Privacy/secrets gate for #6 — transcripts often contain ephemeral tokens, paths, names | Regex-based redaction (high-entropy strings, `Authorization:`, `password=`, `*_TOKEN=`); diff-confirm before commit |
| 8 | `*.jsonl filter=lfs` in `.gitattributes` | Transcript blobs (often MB) bloat normal git history | Add to repo `.gitattributes` for projects that opt into transcript commits |
| 9 | Default-NO consent on save prompt | Privacy-first: an engineer must explicitly type `y` — never default-on | Hard-coded default in `/refocus-complete` prompt |

**Not on this list — concurrent `/context-save`:** every engineer works off a local clone and merges via git, so file-level concurrency at write time is a non-issue. Two engineers updating `docs/context/*` in parallel surface as ordinary git merge conflicts, which AI-assisted resolution handles cleanly. No file-lock or atomic-rename machinery needed.

**Sequencing if/when adopted:** items 1, 3, 4 (brief-schema additions) are zero-risk and can ship anytime. Items 6–9 cluster: don't ship #6 without #7 and #9. Items 2, 5 are independent quality-of-life and can land last.

**Trigger conditions** — adopt an item when one of these appears:
- A postmortem needs reasoning that isn't in the brief → #3, #4, then #6+#7+#9.
- A 24×7 rotation forms → #1, #2.
- `INDEX.md` count exceeds ~50 across the org → #5.

---

*Once /refocus exists, every session in this ecosystem can stop being an unintentional accumulator of cross-cutting context. Knowledge lives where work is. Future sessions inherit history naturally just by `cd`-ing in.*
