| name | upgrade-project |
| description | Upgrade a project to the latest nmg-sdlc contract — relocate legacy `.codex/steering/` and `.codex/specs/` to the project root, update specs, steering docs, and configs to current template standards. Use when user says 'upgrade project', 'update templates', 'check for outdated docs', 'sync with latest plugin', 'relocate specs', 'how do I update my project', or 'bring my project up to date'. Detects the legacy `.codex/{steering,specs}` directory layout and migrates it in place via `git mv`, then diffs headings against current templates and merges missing sections while preserving all user content. Utility skill — run after plugin updates, outside the main SDLC pipeline. |
Upgrade Project
Read ../../references/codex-tooling.md when the workflow starts — it maps legacy tool wording to Codex-native file inspection, shell, editing, web, interactive-gate, and subagent behavior.
Read ../../references/interactive-gates.md when the workflow reaches any manual-mode user decision, menu, review gate, or clarification prompt — Codex asks through request_user_input in Plan Mode, then finalizes a <proposed_plan> before execution.
Bring an existing project forward to the current nmg-sdlc contract. The skill covers two related jobs:
- Directory relocation — move
.codex/steering/ → steering/ and .codex/specs/ → specs/ at the project root (current Codex releases protect .codex/ from Edit/Write; canonical SDLC artifacts must live at the root).
- Template reconciliation — diff existing steering docs, spec files, and runner configs against current templates and merge missing sections while preserving all user content.
$nmg-sdlc:upgrade-project is the only pipeline skill that resolves the legacy-layout gate from ../../references/legacy-layout-gate.md — every other skill aborts on the legacy layout and points users here.
This skill is self-updating: it reads templates at runtime, so when templates gain new sections, this skill detects them automatically without any code changes.
When to Use
- Immediately after upgrading the nmg-sdlc plugin on a project that still uses the legacy
.codex/steering/ and .codex/specs/ layout (these paths are now refused by Codex).
- When steering docs or specs were created with an older plugin version.
- To check whether project files are up to date with current standards.
Unattended Mode
Read ../../references/unattended-mode.md when applying defaults without prompts. This skill applies non-destructive changes automatically in unattended mode and skips destructive operations (which require interactive approval).
| Class | Examples | Unattended-mode behaviour |
|---|
| Non-destructive | Legacy directory relocation, exclusions-file rename, steering doc section additions, spec section additions, Related Spec corrections, frontmatter migration (Issue → Issues, Change History additions), runner config key additions, stale runner-config plugin-root path refreshes, CHANGELOG fixes, VERSION updates, solo feature-/bug- renames, managed contribution-guide creation or update, managed AGENTS.md spec-context guidance creation or update, README contribution-link insertion, managed contribution-gate workflow creation or update, managed issue-form creation or approved target-path replacement | Auto-applied; recorded in the Step 9 summary |
| Destructive | Spec directory consolidation, legacy spec-directory deletes (Steps 4b–4e) | Skipped; recorded under "Skipped Operations (Unattended-Mode)" |
| Informational only | Generic config value drift (Step 5) | Reported in summary but NOT applied — value updates may represent intentional customizations and require explicit per-value approval. Stale plugin-root path refreshes are semantic repairs for unusable paths, not generic drift. |
When .codex/unattended-mode does NOT exist, all interactive behavior is preserved unchanged — present all findings via request_user_input gate per Step 8.
What Gets Analyzed
.codex/steering/ — Legacy steering directory (relocated in Step 1.5)
.codex/specs/ — Legacy spec directory (relocated in Step 1.5)
.codex/migration-exclusions.json — Legacy exclusions file (renamed in Step 1.5 to upgrade-exclusions.json)
steering/*.md — Steering docs (product, tech, structure, retrospective)
specs/*/{requirements,design,tasks}.md — Spec files (feature + defect variants)
specs/*/ — Spec directory naming (legacy `{issue#}-{slug}` vs feature-/bug-)
specs/feature-*/*.md — Spec frontmatter format (`**Issue**` → `**Issues**`, Change History)
.codex/upgrade-exclusions.json — Declined sections (read to skip, written after user declines)
sdlc-config.json — SDLC runner config (key merge + stale plugin-root path refresh + value drift)
CHANGELOG.md — Changelog format and completeness (Keep a Changelog)
VERSION — Single source of truth for project version
CONTRIBUTING.md — Managed non-destructive contribution guide
AGENTS.md — Managed non-destructive nmg-sdlc spec-context guidance
.github/workflows/nmg-sdlc-contribution-gate.yml — Managed non-destructive GitHub Actions contribution gate
.github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml — Managed GitHub Issue Form for SDLC-ready issues
README.md — Existing README gets an idempotent contribution-guide link when present
feature.gherkin files are NOT analyzed — they are generated, not templated.
Read ../../references/spec-frontmatter.md when validating or migrating any spec file's frontmatter — Step 4 and Step 4f both depend on the canonical conventions documented there.
Read ../../references/contribution-guide.md when analyzing or applying contribution-guide findings — the shared contract defines managed CONTRIBUTING.md creation/update, existing guide preservation, README-link insertion, steering-derived content, unattended behavior, and summary statuses.
Read ../../references/project-agents.md when analyzing or applying project-AGENTS findings — the shared contract defines managed root AGENTS.md spec-context guidance, existing instruction preservation, unattended behavior, and summary statuses.
Read ../../references/contribution-gate.md when analyzing or applying contribution-gate findings — the shared contract defines the managed GitHub Actions workflow path, marker/version, safe update rules, path-collision behavior, and stable status output.
Read ../../references/issue-form.md when analyzing or applying issue-form findings — the shared contract defines the managed GitHub Issue Form path, canonical template source, overwrite rule, preservation rule, and stable status output.
Workflow
Before Step 1: Check whether .codex/unattended-mode exists in the project root. Set an unattended-mode flag for the entire session — re-reading the file at each branch point would invite drift.
Step 1: Resolve Template Paths
Locate the template directories from the installed plugin. Use this skill's own file path to resolve paths relative to the plugin root:
- Steering templates:
../onboard-project/templates/*.md — product.md, tech.md, structure.md.
- Retrospective template:
../run-retro/templates/retrospective.md → steering/retrospective.md.
- Spec templates:
../write-spec/templates/*.md — requirements.md, design.md, tasks.md.
- Config template:
scripts/sdlc-config.example.json (resolved from the plugin root).
Use file discovery to find the skill's own SKILL.md path, then resolve ../.. to get the plugin root. Read all template files. If a template file cannot be found, skip that category and note it in the summary.
Step 1.5: Detect And Relocate Legacy Layout
Read references/detection.md when this step runs — the detection signals, preflight checks, interactive proposal, and post-conditions live there. Skip the rest of this section and proceed to Step 2 once detection.md returns.
Step 2: Scan Project Files
file discovery for existing project files using the new canonical paths:
steering/*.md
specs/*/requirements.md
specs/*/design.md
specs/*/tasks.md
sdlc-config.json
CONTRIBUTING.md
AGENTS.md
.github/workflows/nmg-sdlc-contribution-gate.yml
.github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml
README.md
Analyze existing files by default. Missing files may be created only when the current upgrade contract names them as managed project artifacts. CONTRIBUTING.md is managed; create or update it only through ../../references/contribution-guide.md after steering docs exist. AGENTS.md is managed only for the nmg-sdlc spec-context section; create or update it only through ../../references/project-agents.md after steering docs exist. .github/workflows/nmg-sdlc-contribution-gate.yml is managed; create or update it only through ../../references/contribution-gate.md and only when the path is absent or already nmg-sdlc-owned. .github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml is managed; create or replace that exact target path only through ../../references/issue-form.md. Do not synthesize unrelated project files, never create a missing README.md, never overwrite an unmanaged workflow, and never overwrite unrelated issue templates.
Step 3: Analyze Steering Docs
For each existing steering doc (e.g., steering/product.md):
- Read the template file (e.g.,
../onboard-project/templates/product.md).
- Extract template content — steering templates from
onboard-project/templates/ wrap their content in a ```markdown ... ``` code block; parse only the content between the opening ```markdown and the closing ```. The retrospective template (run-retro/templates/retrospective.md`) is direct markdown — use the file content as-is.
- Parse headings — extract all
## headings from both the template content and the existing project file.
- Diff headings — identify headings present in the template but absent from the project file.
- Filter by relevance — for each missing heading, check whether it matches a keyword in the Relevance Heuristic Table in
references/upgrade-procedures.md. If it matches, use file discovery to check the project codebase for the associated evidence patterns. If no evidence is found, exclude the section from the proposal. If the heading does not match any keyword (unknown section), conservatively include it — let the user decide.
- Filter by exclusions — read
.codex/upgrade-exclusions.json from the project root (if it exists). If the file exists but contains invalid JSON, treat it as empty (log a warning and proceed). If the current file's name (e.g., tech.md) appears in excludedSections and the missing heading text appears in that array, skip the section — it was previously declined by the user.
- Extract missing sections — for each remaining missing heading, extract the full section content from the template (from the
## heading to the next ## heading or end of content).
- Determine insertion point — insert after the predecessor heading in template order. If the template order is
## A, ## B, ## C and ## B is missing, insert it after the ## A section's content.
Read references/upgrade-procedures.md when you need the Relevance Heuristic Table (keyword-to-glob mapping) or the Exclusion File Schema (.codex/upgrade-exclusions.json format).
Step 4: Analyze Spec Files
For each spec file (requirements.md, design.md, tasks.md) in each spec directory:
-
Detect the variant — read the first # heading:
- Feature variant:
# Requirements:, # Design:, # Tasks:.
- Defect variant:
# Defect Report:, # Root Cause Analysis:, # Tasks: with a flat summary table (Task/Description/Status columns).
-
Extract the correct template variant — each spec template file contains two code blocks:
- First
```markdown ``` block = feature variant.
- Second
```markdown ``` block (after # Defect heading) = defect variant.
Select the block matching the detected variant.
-
Same heading-diff logic as Step 3 — parse ## headings, identify missing, extract section content, determine insertion point.
Variant detection rules for tasks.md (both variants start with # Tasks:):
- Summary table columns
Phase | Tasks | Status → feature variant.
- Summary table columns
Task | Description | Status → defect variant.
Skip feature.gherkin files entirely — they are generated, not templated.
Step 4a: Validate Related Spec Links
For each defect spec found in Step 2 (identified by a # Defect Report: first heading), read the **Related Spec**: field and validate it:
- Check target exists — verify the target directory exists and contains a
requirements.md.
- Check target is a feature spec — read the target's first heading:
# Requirements: → valid feature spec link. No action needed.
# Defect Report: → target is another defect spec. Follow its Related Spec link recursively (maintaining a visited set to detect cycles) until reaching a # Requirements: heading or a dead end.
- Record findings for each invalid link:
- Current link: the path in the defect spec's
Related Spec field.
- Suggested correction: the resolved root feature spec path, or
N/A — no feature spec found if the chain is circular or broken.
- Skip defect specs that have no
Related Spec field or whose Related Spec is already N/A.
Steps 4b–4f: Legacy Spec-Directory Migration
Read references/migration-steps.md when any legacy {issue#}-{slug} directories were detected in Step 2 or any feature specs still carry singular **Issue** frontmatter — the five sub-steps (detect, cluster, present, apply, frontmatter migration) live there.
Steps 5–7: Config, CHANGELOG, and VERSION Analysis
Read references/verification.md when reaching Steps 5, 6, or 7 — the analysis logic for sdlc-config.json (key merge + stale plugin-root path refresh + value drift), CHANGELOG.md (Keep a Changelog reconciliation), and VERSION (semver consistency) lives there.
Step 7a: Analyze Contribution Guide
Apply ../../references/contribution-guide.md as a managed-artifact analysis after steering docs have been scanned. Record findings for:
- Missing
CONTRIBUTING.md when steering exists.
- Existing
CONTRIBUTING.md missing nmg-sdlc issue/spec/steering coverage.
- Existing
README.md missing a link to CONTRIBUTING.md.
- Missing
README.md, recorded as README.md link: skipped (README missing) without creating the file.
Treat missing-guide creation, targeted guide-section insertion, and README-link insertion as non-destructive managed-artifact changes. If steering is incomplete, skip guide changes and record the missing steering docs as gaps.
Step 7b: Analyze Project AGENTS
Apply ../../references/project-agents.md as a managed-artifact analysis after contribution-guide analysis. Record findings for:
- Missing root
AGENTS.md when steering exists.
- Existing
AGENTS.md missing nmg-sdlc bounded spec-context guidance.
- Existing managed section that is stale or incomplete.
- Existing equivalent project-authored guidance.
- Malformed managed markers.
Treat missing-file creation, managed-section insertion, and managed-section refresh as non-destructive managed-artifact changes. If steering is incomplete, skip AGENTS.md changes and record the missing steering docs as gaps.
Step 7c: Analyze Contribution Gate
Apply ../../references/contribution-gate.md as a managed-artifact analysis after project-AGENTS analysis. Record findings for:
- Missing
.github/workflows/nmg-sdlc-contribution-gate.yml.
- Existing managed workflow with a lower numeric managed version than the current contract.
- Existing managed workflow already at the current version.
- Existing managed workflow with a higher numeric managed version.
- Existing unmanaged file at the approved path.
Treat missing workflow creation and outdated managed workflow replacement as non-destructive managed-artifact changes. Treat future managed versions and unmanaged path collisions as skipped gaps. Preserve all unrelated workflows under .github/workflows/.
Step 7d: Analyze Issue Form
Apply ../../references/issue-form.md as a managed-artifact analysis after contribution-gate analysis. Record findings for:
- Missing
.github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml.
- Existing form whose content matches the canonical template.
- Existing target-path file whose content differs from the canonical template.
- Canonical template read failures.
Treat missing form creation and differing target-path replacement as managed project artifact changes. In unattended mode, auto-apply both states and record the outcome without prompting. Preserve all unrelated issue templates under .github/ISSUE_TEMPLATE/ and all unrelated workflows under .github/workflows/.
Step 8: Present Findings
Display a per-file summary of all proposed changes grouped by category — Legacy Layout Relocation (Step 1.5), Steering Docs (Step 3), Spec Files (Step 4), Spec Directory Consolidation (Step 4b–4e), Spec Frontmatter Migration (Step 4f), Runner Config (Step 5 keys and stale path refreshes), Config Value Drift (Step 5 scalars), Related Spec Links (Step 4a), CHANGELOG (Step 6), VERSION (Step 7), Contribution Guide (Step 7a), Project AGENTS (Step 7b), Contribution Gate (Step 7c), and Issue Form (Step 7d). If everything is up to date, report Everything is up to date — no upgrade needed. and stop.
The approval flow has four parts:
If .codex/unattended-mode exists: Skip Parts A/B/C/D approval prompts. Auto-select all proposed steering doc sections (equivalent to selecting all). Auto-approve all non-destructive changes (legacy layout relocation already applied in Step 1.5, solo renames already applied in Step 4d). Record any remaining destructive operations as skipped operations. Config value drift is reported but NOT applied — skip Part C entirely. Proceed directly to Step 9.
If .codex/unattended-mode does NOT exist: Follow the interactive approval flow below.
Part A: Steering doc sections (per-section approval)
If there are proposed steering doc sections, present a request_user_input gate with options to apply all proposed sections, decline all proposed sections, or choose a subset through the free-form Other answer. List each section in the Plan Mode context before the gate using labels like tech.md: Testing Standards plus a brief intent. Sections the user does not select are treated as declined and persisted in Step 9. Skip Part A if all sections were filtered.
Part B: Spec directory consolidations and other batched changes
Per-group request_user_input gate for each spec directory consolidation or rename from Steps 4b–4e (Yes, consolidate / Skip — leave as-is); a free-form Other answer is treated as "Skip" with the text persisted as the reason. For spec frontmatter migrations, spec file sections, Related Spec corrections, runner config keys, stale runner-config path refreshes, CHANGELOG fixes, VERSION changes, contribution-guide/README-link changes, project-AGENTS changes, contribution-gate workflow changes, or issue-form changes, ask as a single batch (Yes, apply all / No, cancel); a free-form Other answer is treated as a request to narrow the batch, then the batch is re-presented. Skip Part B if there are no non-steering changes.
Part C: Config value drift (per-value approval)
If Step 5 found drifted scalars, present a request_user_input gate with options to apply all drifted scalar values, decline all, or choose a subset through the free-form Other answer. List each scalar in the Plan Mode context before the gate using labels like dotted.key.path: current → template plus brief context about the key's purpose. Unselected values are left unchanged — drift is re-evaluated every run (no exclusions persistence for drift). Skip Part C if no drift was found.
Part D: Recommended runner defaults diff (batch approve)
This flow is additive — Parts A/B/C are unchanged. Part D specifically surfaces changes to the per-step model / effort / timeoutMin defaults so users upgrading across plugin versions can adopt the shipped recommendations without clicking through each field individually.
- Build the diff for each step in
steps.* against scripts/sdlc-config.example.json. Include only fields where the user's value differs from (or inherits a value different than) the shipped example. Present unset/inherited values as (unset — inherited "<global>") so the source of each value is visible.
- Present the diff in a single
request_user_input gate with three options:
Apply all recommended defaults.
Review each field individually (falls back to Part C behavior).
Decline — keep my current values.
- Apply on approval updates each listed field via Codex editing, preserving JSON formatting. "Review individually" falls through to Part C. "Decline" leaves values unchanged. A free-form
Other answer is treated as "Review each field individually" with the text used to preselect or exclude named fields when possible.
- Unattended mode: Part D is not applied — the diff is recorded in the upgrade summary under "Recommended defaults (not applied)". Automatic runs never overwrite user-configured values.
Step 9: Apply Changes
Read references/upgrade-procedures.md when applying Step 9 changes — the detailed apply procedures live there. In summary:
-
Legacy layout relocation — already applied in Step 1.5 (directory moves via git mv, cross-reference rewrites, exclusions-file rename). Note in summary for visibility.
-
Spec directory consolidation — apply merges from Step 4e (create directories, merge files, update cross-references, remove legacy directories).
-
Spec frontmatter migration — apply updates from Step 4f (replace **Issue**: → **Issues**:, insert Change History sections).
-
Markdown files — insert missing sections after their predecessor heading using Codex editing. Add --- separator matching file style. Re-read to verify.
-
Related Spec corrections — replace **Related Spec**: lines with resolved feature spec paths.
-
JSON config — add missing keys only; never overwrite existing values.
Exception: approved or unattended stale plugin-root path-refresh findings from references/verification.md update only unusable path fields after replacement validation.
-
Config value drift updates — for each user-selected drifted value from Part C (interactive only; skipped in unattended): read, Codex editing to replace the old value with the template default, re-read to verify. Preserve all unselected values.
-
Contribution guide — apply approved or unattended-managed CONTRIBUTING.md creation/update and README-link insertion through ../../references/contribution-guide.md; re-read both files when present and record created, updated, already present, added, or skipped statuses.
-
Project AGENTS — apply approved or unattended-managed root AGENTS.md creation/update through ../../references/project-agents.md; re-read the file when present and record created, updated, already present, or skipped statuses.
-
Contribution gate — apply approved or unattended-managed .github/workflows/nmg-sdlc-contribution-gate.yml creation/update through ../../references/contribution-gate.md; re-read the workflow when present and record created, updated, already present, or skipped statuses.
-
Issue form — apply approved or unattended-managed .github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml creation/replacement through ../../references/issue-form.md; re-read the issue form when present and record created, overwritten, already present, or skipped statuses.
-
Persist declined sections — if interactive, save unselected steering doc sections to .codex/upgrade-exclusions.json. Skip in unattended mode.
-
Output summary — report changes applied (including contribution-guide outcomes, project-AGENTS outcomes, contribution-gate outcomes, issue-form outcomes, drift updates, and the legacy layout relocation), declined, skipped, and filtered sections with recommendations.
-
Skipped Operations (Unattended-Mode) — if running unattended and any destructive operations were skipped, emit a machine-readable block:
## Skipped Operations (Unattended-Mode)
The following destructive operations were skipped because `.codex/unattended-mode` is active.
Run `$nmg-sdlc:upgrade-project` interactively to apply them.
| Operation Type | Affected Paths | Reason |
|---------------|----------------|--------|
| consolidation | `42-add-dark-mode/` + `71-dark-mode-toggle/` → `feature-dark-mode/` | Destructive operation requires interactive approval |
Omit this section if no destructive operations were skipped.
Key Rules
- Never modify existing content — only insert new sections or add new keys.
- Create only managed non-destructive files —
CHANGELOG.md, VERSION, .codex/upgrade-exclusions.json, CONTRIBUTING.md, AGENTS.md, .github/workflows/nmg-sdlc-contribution-gate.yml, and .github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml may be created when missing under their documented contracts. Do not synthesize unrelated project files, never create a missing README.md, never overwrite an unmanaged workflow at the contribution-gate path, and never overwrite unrelated issue templates.
- Overwrite only the approved issue-form path —
.github/ISSUE_TEMPLATE/nmg-sdlc-ready-issue.yml is nmg-sdlc-owned and may be replaced from ../../references/issue-form.md when it differs from the canonical template. No other .github/ISSUE_TEMPLATE/ file may be changed.
- Never overwrite values — for JSON, only add absent keys. Exceptions: stale plugin-root path-refresh findings update only unusable path fields after a replacement root passes shape validation; config value drift updates are applied only with explicit per-value user approval (Step 8 Part C). In unattended mode, stale path refreshes may apply, but generic value drift is never applied.
- Skip
feature.gherkin — generated, not templated.
- Interactive by default — when
.codex/unattended-mode is absent, present findings with per-section approval for steering docs and wait for user selection before applying.
- Unattended-mode aware — auto-apply all non-destructive changes; skip destructive operations and report them. Managed issue-form target-path replacement is allowed only because
../../references/issue-form.md declares that exact path as nmg-sdlc-owned.
- Self-updating — read templates at runtime; never hardcode template content.
- Filter irrelevant sections — use codebase analysis to exclude sections with no evidence of relevance; persist user declines in
.codex/upgrade-exclusions.json (interactive only).
- Conservative defaults — when a missing section's heading doesn't match any keyword in the heuristic table, include it and let the user decide.
- Preserve runtime artifacts — never relocate
.codex/unattended-mode or .codex/sdlc-state.json; only the exclusions file is renamed.
Integration with SDLC Workflow
Run this skill periodically after plugin updates to keep project files current:
$nmg-sdlc:onboard-project (one-time)
↓
$nmg-sdlc:upgrade-project (after plugin updates)
↓
$nmg-sdlc:draft-issue → $nmg-sdlc:start-issue → $nmg-sdlc:write-spec → $nmg-sdlc:write-code → $nmg-sdlc:simplify → $nmg-sdlc:verify-code → $nmg-sdlc:open-pr → $nmg-sdlc:address-pr-comments
Next step: Once the upgrade completes, resume your normal SDLC workflow — run $nmg-sdlc:draft-issue for new work or $nmg-sdlc:start-issue to pick up an existing issue.