deft-directive-sync · git:20260804.96cf68f · 2026-08-04 · sha256 4277b5cd1ef4197e
deft-directive-sync git:20260804.96cf68fA
Immutable. This exact content never changes and is served at /api/v1/blob/4277b5cd1ef4197e.
---
name: deft-directive-sync
description: >-
Session-start framework sync and upgrade handoff. Refreshes deposit via npm
+ directive/deft update, validates xBRIEF lifecycle, detects stale origins
(RFC D12), and finishes SCM release handoff in released | pr-open |
blocked:<reason> (#1604).
triggers:
- good morning
- update deft
- update directive
- upgrade framework
- update xbrief
- sync frameworks
---
<!-- AUTO-GENERATED by task packs:render -- DO NOT EDIT MANUALLY -->
<!-- Purpose: rendered skill -->
<!-- Source of truth: packs/skills/skills-pack-0.1.json -->
<!-- Regenerate with: task packs:render -->
<!-- Edit the source, not this file. Slice instead of loading every SKILL.md: task packs:slice skills by-trigger --trigger <kw> (or list) -->
# Deft Directive Sync
Session-start framework sync and upgrade handoff -- refresh the framework deposit via npm + `directive update` / `deft update`, validate xBRIEF lifecycle structure, detect stale origins (RFC D12), then finish SCM release handoff in a named terminal state (#1604).
> **Canonical bootstrap / update path (#761 / #1604):** Install and upgrade via npm: `npm i -g @deftai/directive` (install) or `npm i -g @deftai/directive@latest` (upgrade); Node >= 20 is required. Then from the project root run `directive update` (or `deft update`) to refresh `.deft/core/`, optionally `deft migrate` for npm provenance, and `directive doctor` / `deft doctor` / `task doctor` to confirm deposit health. For machines without Node, the frozen legacy Go installer (`deft-install` / platform-specific `install-*` from GitHub Releases) is a no-Node bootstrap bridge (#1912) -- migrate to npm once Node is available. Legacy `run upgrade` / `task upgrade` are metadata-only acknowledgment (they do NOT replace the payload). **Git-submodule / `task framework:doctor` paths are back-compat only** -- Phases 1-2 below are the legacy update flow, de-emphasized in UPGRADING.md / README. Deposit success is not upgrade released; Phase 8 records one terminal state: `released` | `pr-open` | `blocked:<reason>`. See UPGRADING.md and #761 / #1912 / #1604.
Legend (from RFC2119): !=MUST, ~=SHOULD, ≉=SHOULD NOT, ⊗=MUST NOT, ?=MAY.
## Platform Requirements
! This skill requires **GitHub** as the SCM platform and the **GitHub CLI (`gh`)** to be installed and authenticated for origin freshness (Phase 5) and for the PR path of Phase 8 SCM release handoff. Origin freshness checks fetch issue data via REST-equivalent `gh` surfaces (prefer `gh api repos/<owner>/<repo>/issues/<N>` over GraphQL-heavy forms when under rate pressure; #954).
## When to Use
- User says "good morning", "update deft", "update directive", "upgrade framework", "update xbrief", or "sync frameworks"
- Beginning of a new session where framework updates may be available
- After a known upstream deft / `@deftai/directive` release
- After a successful local deposit when the default branch still lacks the framework update
## Missing CLI / PATH remediation
! When `directive`, `deft`, or the global npm bin is missing from PATH (or `npm i -g @deftai/directive@latest` has not been run), surface actionable install remediation first:
```bash
npm i -g @deftai/directive@latest
```
(or the pnpm equivalent: `pnpm add -g @deftai/directive@latest`). Then re-run `directive update` / `deft update` and `directive doctor`.
⊗ Send the operator to manual GitHub release-asset archaeology or Go installer discovery as the happy path when Node is available -- npm is the primary remediation (#761 / #1604).
## Session orientation — unmanaged header (#2065)
! The region of AGENTS.md **above** the `<!-- deft:managed-section ... -->` marker is project-owned, preserved verbatim on refresh, and **not** freshness-checked by `deft doctor`.
- ! Do NOT treat that unmanaged header as the work queue — consult `deft triage:queue`, `xbrief/` lifecycle, GitHub issues, and `PROJECT-DEFINITION.xbrief.json` instead (#1149, #2065 Option A).
- ⊗ Do NOT add or revive `Status`, `Next:`, or `Known Issues` blocks in AGENTS.md — they duplicate authoritative sources and rot silently while the managed section stays current.
## Framework Events Emitted Here
! When this skill responds to a context-window shift or an explicit "are you using Deft?" probe (per AGENTS.md Deft Alignment Confirmation), emit the paired `session:interrupted` -> `session:resumed` framework events via `scripts/_events.py` so observability of agent-runtime state transitions is structural, not prose-only:
- ! Before re-confirming alignment: `python -m scripts._events emit session:interrupted --session-id <id> --reason context-window-shift`
- ! Immediately after the alignment confirmation line: `python -m scripts._events emit session:resumed --session-id <id> --interrupted-id <id-from-prior-emit>`
- ⊗ Emit a `session:resumed` whose `interrupted_id` does not reference a prior `session:interrupted` -- such records are orphan and rejected by `scripts._events.validate_pairing` (#635 events behavioral wiring)
## Pre-Cutover Detection Guard
! Before proceeding with sync, detect whether the project uses the pre-v0.20 document model and report model state.
### Detection Criteria
A project is **pre-cutover** if ANY of the following are true. This prose mirrors the executable helper in `scripts/_precutover.py`; when in doubt, the helper is canonical.
1. `SPECIFICATION.md` exists and is neither a deprecation redirect nor a current generated spec export. A current generated spec export contains `<!-- Purpose: rendered specification -->` and `<!-- Source of truth: xbrief/specification.xbrief.json -->`, and `xbrief/specification.xbrief.json` plus all five lifecycle folders exist.
2. `PROJECT.md` exists and contains neither the legacy `<!-- deft:deprecated-redirect -->` sentinel NOR the current `Purpose: deprecation redirect` canonical-banner marker (real content, not a deprecation redirect)
3. `xbrief/specification.xbrief.json` exists but the lifecycle folders (`xbrief/proposed/`, `xbrief/pending/`, `xbrief/active/`, `xbrief/completed/`, `xbrief/cancelled/`) do NOT exist
### Action on Detection
! If pre-cutover state is detected, display the actionable migration message, then **skip Phases 0-6** and proceed directly to Phase 7 with the Document Model line set to "pre-v0.20 (legacy)". Phase 8 still applies if a local migration/framework change must land on the default branch after the frozen migrator path:
> "This project uses the pre-v0.20 document model. Current npm releases no longer ship in-product `task migrate:vbrief` (#2068). Follow UPGRADING.md § Frozen pre-v0.20 document-model migration: pin framework v0.59.0, install Python 3.11+ and uv, run `task migrate:vbrief` once from that payload, then upgrade to current npm."
! Include specific details about what was detected:
- Missing lifecycle folders: "Create lifecycle folders via the frozen v0.59.0 migrator (#2068), or manually add `xbrief/{proposed,pending,active,completed,cancelled}/` after migrating narratives"
- `SPECIFICATION.md` with real content: "SPECIFICATION.md contains non-redirect content -- this file is deprecated; use scope xBRIEFs in `xbrief/` instead"
- `PROJECT.md` with real content: "PROJECT.md contains non-redirect content -- this file is deprecated; use `PROJECT-DEFINITION.xbrief.json` instead"
- Missing `PROJECT-DEFINITION.xbrief.json`: "Run `task project:render` to generate the project definition"
- Scope xBRIEF in wrong folder: "Status is '{status}' but file is in {folder}/ -- run `task scope:activate <file>` to fix"
### Model State in Sync Output
! Include a **Document Model** line in the Phase 7 summary:
- Pre-cutover detected: "**Document Model**: pre-v0.20 (legacy) -- follow UPGRADING.md § Frozen pre-v0.20 document-model migration (#2068)"
- Post-cutover (lifecycle folders present, no stale artifacts): "**Document Model**: v0.20+ (xBRIEF-centric) -- OK"
- Post-cutover with tampered placeholders: "**Document Model**: v0.20+ with warnings -- SPECIFICATION.md or PROJECT.md contains non-redirect content"
⊗ Skip model state detection during sync -- always report the document model state.
⊗ Silently ignore pre-cutover artifacts -- the user must be informed with an actionable command to fix the state.
## Phase 0 -- Primary upgrade (npm deposit) (#761 / #1604)
! Treat npm + `directive update` / `deft update` as the **primary** consumer upgrade path when an upgrade is authorized. Do not lead with submodule update when Node is available.
### 0a: When mutation is authorized
! **Mutating** engine install / deposit refresh is authorized only when at least one of:
1. The operator used an **explicit upgrade** trigger: `update deft`, `update directive`, `upgrade framework`, or equivalent ("upgrade Directive", "run update").
2. Doctor / payload-staleness already reports the deposit is **behind** and the operator confirmed the upgrade (or autonomous upgrade was pre-approved).
3. CLI is **missing** from PATH -- then Missing CLI remediation may install the global package so doctor/update can run.
! For routine session orientation triggers (`good morning`, `sync frameworks`, plain `update xbrief` without upgrade language):
1. ! Run **read-only** checks: CLI present?, `directive doctor` / `deft doctor` / `task doctor` when available, structure validation (Phases 3+).
2. ! If doctor reports a stale deposit or available upgrade, **report** the recommended command and ask for consent before mutating.
3. ⊗ Run `npm i -g @deftai/directive@latest` or `directive update` / `deft update` on a routine "good morning" without staleness evidence **and** operator consent (or pre-approved autonomous upgrade).
### 0b: Consumer worktree isolation before deposit
! Before any mutating deposit that will be handed off in Phase 8:
1. ! Run `git status --porcelain` at the **project root** (not only the legacy submodule).
2. ! If the worktree or index has non-framework product changes (or any unexpected staged paths), **stop** and either:
- ask the operator to stash / commit product work first, or
- record `blocked:dirty-worktree` and skip deposit mutation,
- or, with explicit consent, isolate product changes (stash including index) so the deposit cannot mix with them.
3. ! After deposit, stage **only** framework-managed paths for the upgrade commit (e.g. `.deft/core/`, managed AGENTS section, hooks, VERSION / marker files). Reconstruct a clean index if needed rather than `git add -A`.
4. ⊗ Create a framework-only commit or PR from a mixed worktree/index that still carries product feature paths.
### 0c: Engine + deposit (when authorized)
1. ! Confirm the global CLI is available (`directive --version` or `deft --version`). If missing, run Missing CLI / PATH remediation above, then continue.
2. ! Upgrade the global engine only when mutation is authorized (0a):
```bash
npm i -g @deftai/directive@latest
```
3. ! From the **project root**, after worktree isolation (0b), refresh the deposit:
```bash
directive update
# or: deft update
```
4. ~ Optionally stamp npm provenance (idempotent): `directive migrate` / `deft migrate`.
5. ! Verify deposit health:
```bash
directive doctor
# or: deft doctor / task doctor
```
6. ! Record whether the working tree now has **framework-only** changes under `.deft/core/`, managed AGENTS section, hooks, or related managed files that need SCM release.
### 0d: Framework-only change-set discipline
! Keep upgrade commits/PRs **framework-only** -- do not mix product feature work into the same commit or PR as the deposit refresh.
⊗ Treat a successful deposit alone as `released` -- the default branch must carry the update (or a PR must be open) before the operator goal is complete (#1604).
⊗ Force a global CLI upgrade or deposit mutation on routine session sync without consent or staleness evidence.
## Phase 1 -- Pre-flight (legacy submodule path)
! **Legacy / back-compat only.** Run Phases 1-2 only when the consumer still uses a `deft/` git submodule layout and cannot use the npm deposit path. Prefer Phase 0 for all npm-managed installs.
! Check that the deft/ submodule working tree is clean before attempting any update.
1. ! Run `git -C deft status --porcelain`
2. ! If output is non-empty (dirty working tree): **stop** and ask user whether to stash (`git -C deft stash`) or abort the sync entirely. Do NOT proceed with a dirty submodule. Record terminal state `blocked:dirty-submodule` if the operator aborts.
3. ! Record the current DEFT commit for later comparison:
```
git -C deft log --oneline -1
```
4. ! Present the current state to the user:
- Current DEFT commit (hash + subject)
- Clean/dirty status
- Confirmation that pre-flight passed (or the blocker if dirty)
## Phase 2 -- Update DEFT Submodule (legacy / back-compat)
! **Legacy / back-compat only** -- not the primary consumer upgrade path (#1604). Submodule update does not replace Phase 0 for npm installs.
1. ! Run the submodule update:
```
git submodule update --remote --merge deft
```
2. ! Show what changed by comparing before/after:
```
git -C deft log --oneline <old-hash>..HEAD
```
3. ~ If no new commits, report "deft submodule already up to date" and proceed to Phase 3.
## Phase 3 -- Structure Validation
! Validate the xBRIEF lifecycle folder structure and project files.
### 3a: Lifecycle Folder Structure
! Verify all required lifecycle folders exist:
1. ! Check that the following directories exist under `./xbrief/`:
- `proposed/`
- `pending/`
- `active/`
- `completed/`
- `cancelled/`
2. ! Report any missing folders with a clear warning:
- "WARNING: xbrief/{folder}/ does not exist -- lifecycle structure is incomplete"
3. ~ If folders are missing, suggest `task migrate:preflight` and the frozen v0.59.0 migrator path (#2068), or creating them manually after migration
### 3b: PROJECT-DEFINITION.xbrief.json Validation
! Validate the project identity gestalt file:
1. ! Check that `./xbrief/PROJECT-DEFINITION.xbrief.json` exists
- If missing: "WARNING: PROJECT-DEFINITION.xbrief.json not found -- run `task project:render` to create"
2. ! If the file exists, validate it is well-formed:
- Valid JSON (`python3 -m json.tool` or equivalent)
- Top-level `xBRIEFInfo` envelope with `version` field equal to `"0.6"`
- `plan` object with `title`, `status`, and `items` fields present
- `plan.narratives` values are plain strings (not objects or arrays)
3. ! **Freshness check**: Compare `xBRIEFInfo.updated` (or `xBRIEFInfo.created` if no `updated`) against recent scope completions:
- Scan `xbrief/completed/` for xBRIEFs with `xBRIEFInfo.updated` timestamps newer than the PROJECT-DEFINITION timestamp
- If stale: "WARNING: PROJECT-DEFINITION.xbrief.json may be stale -- {N} scopes completed since last update. Run `task project:render` to refresh."
### 3c: Validate Root-Level xBRIEF Files
! Validate all `./xbrief/*.xbrief.json` files at the xbrief root:
1. ! Check each file is valid JSON
2. ! Verify structural conformance:
- Top-level `xBRIEFInfo` envelope with `version` field present
- `plan` object with `title`, `status`, and `items` fields present
- `plan.status` values from valid enum: draft, proposed, approved, pending, running, completed, blocked, cancelled
3. ~ Use `task xbrief:validate` if available for deeper validation
4. ! Report any validation failures with file name and specific violation
⊗ Overwrite or modify project-level `./xbrief/*.xbrief.json` files -- those are project data, not framework files. Report issues and let the user decide how to fix them.
## Phase 4 -- Lifecycle Consistency Check
! Verify that each scope xBRIEF's `plan.status` matches its folder location.
1. ! Scan all scope xBRIEFs in lifecycle folders (`proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`)
2. ! For each xBRIEF, check `plan.status` against the expected statuses for its folder:
- `proposed/`: status should be `draft` or `proposed`
- `pending/`: status should be `approved` or `pending`
- `active/`: status should be `running` or `blocked`
- `completed/`: status should be `completed`
- `cancelled/`: status should be `cancelled`
3. ! Report any mismatches:
- "MISMATCH: {filename} in {folder}/ has status '{status}' -- expected one of [{expected_statuses}]"
4. ~ Per `vbrief/vbrief.md` convention, trust the status field and suggest correcting the folder location:
- "Suggested fix: move {filename} to {correct_folder}/ (status '{status}' is authoritative)"
⊗ Auto-move xBRIEFs to fix folder/status mismatches -- report only; user decides during refinement or ad-hoc
## Phase 5 -- Origin Freshness (RFC D12)
! For xBRIEFs with external origin references, detect staleness and externally-closed origins.
### Step 1: Scan Origins
1. ! For each xBRIEF in `proposed/` and `pending/` with a `github-issue` reference in `plan.references` or top-level `references`:
- Extract the issue number from the reference URL or `id` field
- Fetch the issue: `gh issue view {N} --repo {owner/repo} --json updatedAt,state`
2. ! Compare the issue's `updatedAt` against the xBRIEF's `xBRIEFInfo.updated` (or `xBRIEFInfo.created` if no `updated` field)
### Step 2: Categorize and Report
1. ! **Stale origins** -- issue `updatedAt` is newer than xBRIEF `updated` timestamp:
- "{N} xBRIEFs have origins updated since last sync"
- List each: "{filename}: Issue #{N} updated {time_delta} ago"
2. ! **Externally closed origins** -- issue state is `CLOSED`:
- "{N} xBRIEFs have origins that were closed externally"
- List each: "{filename}: Issue #{N} is closed ({close_reason})"
3. ~ **Current origins** -- no changes detected (report count only)
### Step 3: Recommendation
- ! Report only -- never auto-update xBRIEFs based on origin changes
- ~ If stale or externally-closed xBRIEFs are found, suggest: "Run a refinement session (`skills/deft-directive-refinement/SKILL.md`) to reconcile stale origins with user approval."
⊗ Auto-update xBRIEFs based on origin freshness checks -- report only; user decides during refinement
## Phase 6 -- Framework Sync
After structure validation, sync framework-level assets.
### 6a: Check AGENTS.md freshness
~ Compare the project's `AGENTS.md` against the deft template (if a template exists in the updated deposit / `.deft/core/` or legacy `deft/` submodule):
1. ~ Diff the structure (section headings, key rules) rather than expecting byte-identical content
2. ~ Report any new sections or rules added upstream that are missing locally
3. ~ Do NOT auto-overwrite -- present differences and let the user decide
4. ~ If the unmanaged header still carries `Status`, `Next:`, or `Known Issues`, recommend replacing them with the **Session orientation** pointer at `xbrief/` + triage + issues (#2065 Option A) -- do NOT treat that header prose as the work queue
### 6b: Check codebase MAP freshness
~ If `./.planning/codebase/MAP.md` exists, or `PROJECT-DEFINITION.xbrief.json` declares a `projectionManifest[]` entry with `kind: "codebase-map"`, run `task verify:codebase-map-fresh` when the command resolves. If it reports drift, recommend `task codebase:map` and note that the generated MAP is advisory unless the operator asked to refresh projections.
- ! Keep `plan.architecture.codeStructure` and configured provider artifacts authoritative; the MAP is a generated projection.
- ⊗ Auto-edit canonical xBRIEF metadata to make the MAP fresh during sync -- report drift and let the operator choose a follow-up.
### 6c: List new skills
! Compare the `skills/` directory (or deposited `.deft/core/` skills) before and after the update:
1. ! List any new skill directories added in the update
2. ~ For each new skill, read its frontmatter `description` field and present a one-liner
3. ~ Mention if any existing skills were updated (changed files)
## Phase 6d -- Legacy Artifact Review (post-migration, one-time)
! If `xbrief/migration/LEGACY-REPORT.md` exists (and has NOT been renamed to `LEGACY-REPORT.reviewed.md`), walk the operator through each captured legacy section and record their disposition inline in the same file. This phase surfaces the non-canonical content that `task migrate:xbrief` preserved via the `LegacyArtifacts` narrative mechanism (#505).
### Detection
1. ! Check for `xbrief/migration/LEGACY-REPORT.md` in the project root.
2. ! If the file is absent or `LEGACY-REPORT.reviewed.md` exists (reviewed form), skip Phase 6d silently and proceed to Phase 7.
3. ! If `LEGACY-REPORT.md` is present and has NOT been renamed, begin the review loop below.
### Review loop
1. ! Present the report summary (sources + per-bucket section counts) to the user.
2. ! For each captured section listed under `## specification.xbrief.json -> LegacyArtifacts`, `## PROJECT-DEFINITION.xbrief.json -> LegacyArtifacts`, and `## PRD.md content (flagged: hand-edited)`:
- Restate the section title, source file + line range, and size.
- Offer exactly three disposition options: **Keep** (leave inside `LegacyArtifacts`), **Fold into {suggested narrative}** (move into a canonical narrative key), or **Drop** (remove from `LegacyArtifacts`, with explicit user confirmation).
- ~ If a sidecar pointer is present (`xbrief/legacy/{stem}-{slug}.md`), open the sidecar for the user before offering options so the full content is visible.
3. ! Record each disposition inline in the same `LEGACY-REPORT.md` file under a new `## Reviewed` section with one entry per legacy item: original section, user's decision, target location (if folded) or confirmation note (if kept/dropped), and the reviewer's timestamp.
4. ! For a **Fold** decision, the agent updates the target xBRIEF's narrative key AND deletes only the corresponding section from the `LegacyArtifacts` narrative -- never the file.
5. ! For a **Drop** decision, the agent removes only the corresponding section from the `LegacyArtifacts` narrative.
6. ! Once all sections carry a recorded disposition, rename the file to `LEGACY-REPORT.reviewed.md`. The file is kept so the audit trail remains -- ⊗ MUST NOT delete either form.
### Anti-patterns
- ⊗ Delete `LEGACY-REPORT.md` or `LEGACY-REPORT.reviewed.md` -- these are the migration audit trail and MUST persist.
- ⊗ Auto-dispose of legacy artifacts without user input -- every section requires an explicit decision.
- ⊗ Rename to `.reviewed.md` before every captured section has a recorded disposition in the `## Reviewed` section.
- ⊗ Drop a legacy section without explicit user confirmation (even if the section looks obviously stale).
- ⊗ Silently delete sidecar files under `xbrief/legacy/` -- they are referenced from `LegacyArtifacts` and are part of the audit trail.
## Phase 6e -- Doc-sprawl awareness (advisory, #647)
Doc sprawl is a project-health concern, not just a human-experience one: a lean, well-written AGENTS.md sitting on top of a large reachable doc corpus does **not** stop agents from discovering and loading those docs (Augment Code study, `content/docs/good-agents-md.md`). It degrades agent quality silently until measured. This step **surfaces** the risk; it is ADVISORY and MUST NOT block or fail the sync.
1. ~ Scan the project's reachable documentation footprint: the top-level `docs/` / `_docs/` directories, nested `README.md` files, and any `architecture` / `design` docs.
2. ~ Flag, as a non-blocking nudge, when any of these appear:
- A large `docs/` (or `_docs/`) directory that is **not referenced** from the AGENTS.md reference chain (orphan docs are discovered <10% of the time yet still cost context when found -- the reference-chain contract, #644).
- Deeply nested READMEs that duplicate guidance the reference chain already carries.
- Architecture / design docs that restate what the codebase already shows (a measured overexploration trigger).
3. ~ Point the operator at `content/docs/agent-docs.md` (the empirically-grounded structure pattern) and the `REFERENCES.md` reference-chain contract for remediation. For directive's own always-loaded file, the `verify:agents-md-budget` ratchet (#645) and the consumer advisory (`agentsMdAdvisory`, #2155) are the size guards.
4. ⊗ Do NOT convert this into a hard gate or auto-delete any doc -- the value is the nudge at the right moment; thresholds are a judgment call the operator owns.
## Phase 7 -- Summary
! Present a consolidated summary to the user covering:
1. **Upgrade path used**: npm deposit (Phase 0) / legacy submodule (Phases 1-2) / already up to date
2. **DEFT / deposit version change**: old version or commit -> new (or "already up to date")
3. **Structure validation**: lifecycle folders status (all present / missing folders listed)
4. **PROJECT-DEFINITION status**: valid / missing / stale (with freshness details)
5. **xBRIEF validation results**: pass/fail per file, with details on any failures
6. **Lifecycle consistency**: all consistent / N mismatches found (with details)
7. **Origin freshness**: N stale / N externally-closed / N current (with details)
8. **Document Model**: pre-v0.20 (legacy) / v0.20+ (xBRIEF-centric) OK / v0.20+ with warnings (see Pre-Cutover Detection Guard)
9. **AGENTS.md status**: current / has upstream changes / needs review
10. **Codebase MAP status**: current / stale / absent / not configured (advisory)
11. **New skills**: list any newly added skills with descriptions
12. **Pending SCM release**: whether framework-only changes still need commit/push/PR/merge (Phase 8)
! After a successful deposit (or submodule bump), **do not stop at the local change set**. Proceed to Phase 8 SCM release handoff. If there is nothing to release (already on default branch / no local framework delta), record terminal state `released` when the default branch already carries the current framework update; otherwise name the next release step.
? For the legacy submodule path only, if a bump is ready and the operator has not yet approved a commit, ask: "Shall I commit the submodule update and continue SCM release handoff?" -- do NOT auto-commit without approval. Prefer message:
```
chore(deft): update deft submodule to <short-hash>
```
For npm deposit changes, prefer a framework-only commit message such as:
```
chore(deft): refresh framework deposit to <version>
```
## Phase 8 -- SCM release handoff (#1604)
! After a successful framework deposit (Phase 0) or legacy submodule bump (Phases 1-2), carry the update through consumer SCM release. Installer/update success is not upgrade released.
! Record **exactly one** terminal state when this skill exits after a deposit-related run:
| Terminal state | Meaning |
| --- | --- |
| `released` | Default branch carries the framework update (merged or committed directly under policy). |
| `pr-open` | Framework-only branch pushed and PR opened; awaiting review/merge per policy. |
| `blocked:<reason>` | Explicit blocker (examples: `blocked:dirty-worktree`, `blocked:auth`, `blocked:branch-protection`, `blocked:human-merge-gate`, `blocked:ci`, `blocked:operator-declined`). |
### 8a: Policy detection
1. ! Read consumer branch policy: `plan.policy.allowDirectCommitsToMaster`, `plan.policy.requireHumanMerge`, and any known branch-protection / default-branch rules (`deft policy:show` when available).
2. ! Classify the path:
- **PR path (default when protected or human-merge):** branch protection enabled, or `requireHumanMerge` is true, or direct commits to default branch are disallowed.
- **Direct-commit path:** `allowDirectCommitsToMaster` (or equivalent) is true **and** human-merge is not required **and** branch protection does not forbid the commit.
### 8b: PR-oriented path (branch-protected / human-merge)
1. ! With operator consent (or autonomous consent when the operator already approved upgrade handoff), create a **framework-only** branch (e.g. `chore/deft-update-<version>`), commit framework deposit files only, push, and open a PR targeting the default branch.
2. ! Stop at terminal state **`pr-open`** once the PR URL is available -- unless policy explicitly allows bot merge **and** the operator directed merge.
3. ⊗ Auto-merge past `requireHumanMerge` / the human merge gate (#1193). Agents may open PRs; they do not merge when policy forbids it.
4. ⊗ Claim `released` when the PR is only open or only locally committed.
### 8c: Direct-commit-enabled path
1. ! Present an **explicit** default-branch path with confirmation (do not silently commit to master/main).
2. ! On confirmation, commit framework-only changes on the default branch (or merge the framework branch) and push so the default branch carries the update.
3. ! Record terminal state **`released`** only after the default branch ref includes the framework update.
### 8d: Stop-after-commit is a failure mode
! A local framework-only commit without push/PR/merge **and** without naming the next release step is a **failure mode** of this skill (#1604 historical class).
- ! If the workflow must pause after a local commit, name the next step explicitly (push + open PR, or confirm direct-commit + push) and record `blocked:<reason>` or continue until `pr-open` / `released`.
- ⊗ End the skill at "local framework-only commit done" without a terminal state line.
- ⊗ Report `released` when only a local commit exists and the default branch does not yet carry the update.
### 8e: Terminal state line
! End the skill output with a single machine-readable line operators and agents can grep:
```text
upgrade-handoff: released
upgrade-handoff: pr-open
upgrade-handoff: blocked:<reason>
```
Include the PR URL when state is `pr-open`, and the merge/default-branch SHA when state is `released`.
### 8f: Framework-only path allowlist
! When committing for handoff, include only framework deposit artifacts (managed `.deft/core/`, AGENTS managed section, hooks, VERSION/marker files, and other paths the deposit itself refreshed). Exclude product source, tests, and unrelated staged files. If isolation was used in 0b, restore the operator's product stash only **after** the framework commit is complete (or on a separate branch).
## Anti-Patterns
- ⊗ Auto-commit submodule changes without user approval
- ⊗ Auto-commit or auto-push framework deposit changes without the Phase 8 policy path and consent rules
- ⊗ Stop after a local framework-only commit without naming the next release step or recording a terminal state (#1604)
- ⊗ Claim terminal state `released` when the update is only local or only on an open PR
- ⊗ Auto-merge when `requireHumanMerge` is true or branch protection forbids bot merge (#1193)
- ⊗ Treat git submodule update as the primary consumer upgrade path when npm + `directive update` / `deft update` is available
- ⊗ Send operators to manual GitHub release-asset archaeology when `npm i -g @deftai/directive@latest` is the correct remediation
- ⊗ Overwrite project-level `./xbrief/*.xbrief.json` files -- those are project data
- ⊗ Skip the pre-flight dirty check -- a dirty submodule can cause merge conflicts or data loss
- ⊗ Include a separate fetch of the xBRIEF schema from upstream deftai/xBRIEF -- that is a CI concern (see #128), not a user sync task
- ⊗ Auto-move xBRIEFs to fix folder/status mismatches -- report only; never auto-fix
- ⊗ Auto-update xBRIEFs based on origin freshness -- report only; user decides during refinement
- ⊗ Mix product feature work into a framework-only upgrade commit or PR
- ⊗ Force `npm i -g @deftai/directive@latest` or deposit mutation on routine session sync without staleness evidence and operator consent
- ⊗ Run Phase 8 framework-only commit from a mixed product+framework worktree/index without isolation