deftai

deft-directive-sync

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).

deftai 31 14 Updated 1w ago
GitHub

Install

npx skillscat add deftai/directive/deft-directive-sync

Install via the SkillsCat registry.

SKILL.md

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 Python-launcher 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:

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 task lifecycle:event so observability of agent-runtime state transitions is structural, not prose-only:

  • ! Before re-confirming alignment: task lifecycle:event -- emit session:interrupted --session-id <id> --reason <enum>
  • ! Immediately after the alignment confirmation line: task lifecycle:event -- 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 task lifecycle:event -- 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 task migrate:preflight; 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):
npm i -g @deftai/directive@latest
  1. ! From the project root, after worktree isolation (0b), refresh the deposit:
directive update
# or: deft update
  1. ~ Optionally stamp npm provenance (idempotent): directive migrate / deft migrate.
  2. ! Verify deposit health:
directive doctor
# or: deft doctor / task doctor
  1. ! 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.8" (legacy "0.6" is read-accepted until deft migrate:xbrief)
    • 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 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 externally-closed origins. task reconcile:issues reports linked / unlinked / closed / completed-status drift -- it does not have a stale-content (updatedAt) bucket. Implementation-intent fail-closed for a newer origin is task xbrief:preflight (#3363).

Step 1: Scan Origins

  1. ! Run task reconcile:issues for linked / unlinked / externally-closed / completed-status drift.
  2. ! For each xBRIEF in proposed/ and pending/ with a github-issue reference in plan.references or top-level references, an advisory scan MAY fetch the issue (gh api repos/{owner}/{repo}/issues/{N}) and compare updatedAt / updated_at against xBRIEFInfo.updated (or xBRIEFInfo.created if no updated field). This is report-only; it is not the engine verb.

Step 2: Categorize and Report

  1. ! Externally closed origins -- issue state is CLOSED (from task reconcile:issues):
    • "{N} xBRIEFs have origins that were closed externally"
    • List each: "{filename}: Issue #{N} is closed ({close_reason})"
  2. ! Advisory newer origin -- issue updatedAt is newer than xBRIEF updated timestamp (manual scan or later task xbrief:preflight):
    • "{N} xBRIEFs have origins updated since last sync"
    • List each: "{filename}: Issue #{N} updated {time_delta} ago"
  3. ~ Current origins -- no changes detected (report count only)

Step 3: Recommendation

  • ! Report only -- never auto-update xBRIEFs based on origin changes
  • ~ If newer or externally-closed origins are found, suggest: "Run a refinement session (skills/deft-directive-refinement/SKILL.md) to walk origin changes with user approval. Implementation will fail closed at task xbrief:preflight until the brief is refreshed or intentional divergence is recorded."

⊗ 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:

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