project-claude-organizer
project-claude-organizer
Reads the project
.claude/folder, compares it against the canonical SDD structure, presents a reorganization plan, applies migrations after user confirmation, and optionally deletes source files from.claude/after successful migration with explicit user confirmation.
Triggers: /project-claude-organizer, organize .claude folder, fix project claude structure, align .claude to canonical SDD layout, project claude organizer
Scope note: This skill reads the live
.claude/folder state directly — it does NOT read fromaudit-report.md. The skill that readsaudit-report.mdand applies its corrections isproject-fix. This skill targetsPROJECT_ROOT/.claude/only — it MUST NOT be run against~/.claude/(the user-level runtime).
Organizer Kernel
project-claude-organizer operates as a stable organizer kernel with four stages:
| Stage | Responsibility | Output |
|---|---|---|
| Detect | Read the live .claude/ folder shape and resolve the target paths |
Observed items, resolved project-local target |
| Classify | Split observed items into canonical, legacy-migration, documentation-candidate, and unexpected buckets | Buckets that define the possible organizer actions |
| Propose | Present a dry-run plan before any writes | Explicit user-visible plan and confirmation gate |
| Apply additive migrations | Perform the allowed create/copy/append/scaffold operations after confirmation | Updated project files plus claude-organizer-report.md |
The kernel is intentionally stable. Migration strategies may evolve, but they operate inside this detect, classify, propose, apply-additive flow rather than redefining the command.
Scope Boundaries
project-claude-organizer uses three behavior classes.
| Class | Typical examples | Mutation scope | Confirmation model |
|---|---|---|---|
| Core additive migrations | create missing required items, copy docs/templates, append routed content | Additive writes only | Runs inside the approved plan |
| Explicit opt-in operations | commands/ scaffolding, readme.md user-choice migration, cleanup deletion prompts | Limited writes after explicit category or cleanup confirmation | Requires explicit user choice or confirmation |
| Advisory-only outcomes | unexpected items, skills-audit findings, ambiguous routing, non-qualifying command files | No automatic mutation | Report only |
Notes:
- The organizer is not a generalized transformation engine. If an item does not map cleanly to a supported path, it remains advisory-only.
- Cleanup deletion is a follow-up path after successful migration, not part of the organizer kernel itself.
- Skills audit findings may be important, but they do not expand the organizer's write authority automatically.
Compatibility Policy
Compatibility behavior is a separate policy layer of project-claude-organizer, not an implicit side effect of individual migration handlers.
Compatibility rules currently include:
- Legacy-shape compatibility: known legacy directories and files are treated as migration candidates so projects can be normalized incrementally.
- Advisory compatibility: unsupported or ambiguous structures remain manual-review outcomes instead of forcing speculative organizer mutations.
- Opt-in compatibility: scaffolding, user-choice branches, and cleanup deletion remain explicit opt-in paths even when they are available.
- Audit-adjacent compatibility: skills audit may surface organizer-relevant findings, but those findings remain diagnostic rather than granting organizer permission to rewrite
.claude/skills/automatically.
This policy MUST be explicit whenever compatibility behavior affects whether an item is migrated, preserved, or only reported.
Process
Step 1 — Resolve paths
Determine the project root and the target .claude/ directory.
1.1 — Resolve CWD as project root:
PROJECT_ROOT = current working directory (absolute path).
Normalize all paths to forward slashes for display.
1.2 — Resolve home directory (Windows-compatible):
Use the following priority chain (same as install.sh and claude-folder-audit):
- If
$HOMEis set and non-empty →HOME_DIR = $HOME - Else if
$USERPROFILEis set and non-empty →HOME_DIR = $USERPROFILE - Else if
$HOMEDRIVEand$HOMEPATHare both set →HOME_DIR = $HOMEDRIVE$HOMEPATH - Else → output error: "Cannot resolve home directory." and stop.
1.3 — Set target directory:
PROJECT_CLAUDE_DIR = PROJECT_ROOT/.claude
1.4 — Guard: verify .claude/ exists:
Check whether PROJECT_CLAUDE_DIR exists as a directory.
If it does NOT exist:
No .claude/ folder found at <PROJECT_ROOT>.
This skill targets project .claude/ folders only — not the ~/.claude/ runtime.
It requires a project with an existing .claude/ directory.
Exiting without changes.
Stop. Do not write any files.
1.5 — Guard: prevent targeting ~/.claude/:
If PROJECT_CLAUDE_DIR resolves to the same path as HOME_DIR/.claude, output:
This skill targets project .claude/ folders only — not the ~/.claude/ runtime.
Exiting without changes.
Stop.
Step 2 — Enumerate observed items
List all items (files and directories) one level deep under PROJECT_CLAUDE_DIR.
Do not recurse into subdirectories.
Record each item as:
<name>— for files<name>/— for directories
Collect the result as OBSERVED_ITEMS.
Step 3 — Compare against canonical expected item set
The canonical expected item set for a project .claude/ folder is defined below.
This set is cross-referenced to claude-folder-audit Check P8 and MUST remain consistent with it.
Canonical expected item set (V1):
# Cross-reference: claude-folder-audit Check P8
#
# Required (absence triggers a create action):
CLAUDE.md
skills/
#
# Optional (absence is informational only — not an error):
hooks/
audit-report.md
claude-folder-audit-report.md
claude-organizer-report.md
settings.json
settings.local.json
openspec/
ai-context/
Classification rules:
MISSING_REQUIRED= items in the Required subset that are NOT inOBSERVED_ITEMS- Required items:
CLAUDE.md,skills/
- Required items:
UNEXPECTED= items inOBSERVED_ITEMSthat are NOT in the full canonical expected setPRESENT= items inOBSERVED_ITEMSthat ARE in the canonical expected set
DOCUMENTATION_CANDIDATES classification (runs after the three-bucket classification above):
KNOWN_AI_CONTEXT_TARGETS = [
"stack",
"architecture",
"conventions",
"known-issues",
"changelog-ai",
"onboarding",
"quick-reference",
"scenarios"
]
KNOWN_HEADING_PATTERNS = [
"## Tech Stack",
"## Architecture",
"## Known Issues",
"## Conventions",
"## Changelog",
"## Domain Overview"
]
DOCUMENTATION_CANDIDATES = []
For each .md file currently in UNEXPECTED:
(a) Signal 1 — Filename stem match (case-insensitive):
Extract the file's stem (filename without .md extension). If the stem matches any entry in KNOWN_AI_CONTEXT_TARGETS (case-insensitive):
- Add to
DOCUMENTATION_CANDIDATESwithsource = PROJECT_CLAUDE_DIR/<filename>.md,destination = PROJECT_ROOT/ai-context/<filename>.md,reason = "filename-match". - Remove from
UNEXPECTED. - Do NOT apply Signal 2 for this file.
(b) Signal 2 — Content heading match (for remaining .md files in UNEXPECTED only):
Read the file's content. If any line starts with one of the KNOWN_HEADING_PATTERNS entries (case-sensitive, line-starts-with match):
- Add to
DOCUMENTATION_CANDIDATESwithsource = PROJECT_CLAUDE_DIR/<filename>.md,destination = PROJECT_ROOT/ai-context/<filename>.md,reason = "heading-match". - Remove from
UNEXPECTED.
Files matching neither signal remain in UNEXPECTED — no false promotion.
Scope note: Only root-level
.mdfiles fromOBSERVED_ITEMSare eligible. Subdirectory entries (e.g.extra/) are not scanned recursively — only the top-level directory entry is considered.
Step 3b — Legacy Directory Intelligence
After the DOCUMENTATION_CANDIDATES classification completes, run a second pass over the remaining
items in UNEXPECTED. For each item whose name matches a known legacy directory or file pattern,
reclassify it into LEGACY_MIGRATIONS and remove it from UNEXPECTED. Items that match no known
pattern are left in UNEXPECTED unchanged — the existing "review manually" behavior is preserved
for genuinely unknown items.
LEGACY_MIGRATIONS = []
Items reclassified into LEGACY_MIGRATIONS are removed from UNEXPECTED. Each entry in
LEGACY_MIGRATIONS carries: source (absolute path), destination (one or more proposed
destination paths), strategy (see table below), and confirmation_required = true.
LEGACY_PATTERN_TABLE — quick-scan index (match order top-to-bottom, name match first):
| Pattern name | Match condition | Migration strategy | Destination summary |
|---|---|---|---|
commands/ |
Directory named commands (case-insensitive) |
scaffold — active SKILL.md generation |
For each qualifying .md file: derive skill name from stem (kebab-case), infer format type via 4-signal heuristic, check idempotency (skip if .claude/skills/<stem>/SKILL.md already exists), write SKILL.md skeleton to .claude/skills/<stem>/SKILL.md; non-qualifying files receive advisory notes only; source files NEVER modified or deleted |
docs/ |
Directory named docs (case-insensitive) |
copy — per .md file |
ai-context/features/<name>.md for each .md at immediate docs/ level |
system/ |
Directory named system (case-insensitive) |
append — route by filename |
architecture.md → ai-context/architecture.md; database.md + api-overview.md → ai-context/stack.md |
plans/ |
Directory named plans (case-insensitive) |
copy — route by status |
Active plans → openspec/changes/<plan-name>/; archived plans → openspec/changes/archive/<plan-name>/ |
requirements/ |
Directory named requirements (case-insensitive) |
scaffold — idempotent |
openspec/changes/<YYYY-MM-DD>-<slug>/proposal.md per .md file at immediate level |
sops/ |
Directory named sops (case-insensitive) |
user-choice — per file |
Option A: append section to ai-context/conventions.md; Option B: copy to docs/sops/<filename> |
templates/ |
Directory named templates (case-insensitive) |
copy |
docs/templates/<filename> for each file at immediate templates/ level |
project.md |
Root-level .md file named project.md (case-insensitive) |
section-distribute |
Sections routed to ai-context/stack.md, ai-context/architecture.md, ai-context/known-issues.md by heading signal |
readme.md |
Root-level .md file named readme.md (case-insensitive) |
user-choice |
Option A: append full content to PROJECT_ROOT/CLAUDE.md under marker <!-- .claude/readme.md -->; Option B: copy to PROJECT_ROOT/docs/README-claude.md; idempotency: if marker already present in CLAUDE.md → record "already integrated (skipped)" |
Classification loop:
For each item in UNEXPECTED:
- Match item name (case-insensitive) against
LEGACY_PATTERN_TABLE(top-to-bottom):- On hit: add entry to
LEGACY_MIGRATIONS(source,destination(s),strategy,confirmation_required = true); remove item fromUNEXPECTED. - On miss: item stays in
UNEXPECTED— "review manually" behavior unchanged.
- On hit: add entry to
Scope rule: Only top-level items (directories and root-level files enumerated in
OBSERVED_ITEMS) are evaluated. Step 3b MUST NOT recurse into subdirectories — a directory namedcommands/nested inside another unexpected directory (e.g.extra/commands/) is NOT matched by the pattern.
Pattern detail blocks
Pattern: commands/
- Match condition: Directory named
commands(case-insensitive) - Strategy:
scaffold— active SKILL.md generation per qualifying.mdfile - Destination:
.claude/skills/<stem>/SKILL.md— one SKILL.md skeleton per qualifying file
Scaffold procedure (runs when commands/ category is confirmed in Step 5.7):
-
List all
.mdfiles at the immediatecommands/level only (no recursion into subdirectories). -
If no
.mdfiles are found → output:commands/ — no .md files found at immediate level; nothing to scaffoldStop; no further processing for this category. -
For each
.mdfile found, apply the 4 qualifying markers (any one marker is sufficient to qualify):- (a) Step-numbered sections: the file contains lines matching
### Step N,- Step N, orN.where N is a number (numbered/bulleted process sections) - (b) Trigger / invocation patterns: the file contains lines starting with
/command-name(slash-command references) or lines containing**Triggers**ortrigger:(trigger definitions) - (c) Process headings: the file contains a section heading that is exactly
## Process,## Steps,## How to, or## Instructions - (d) Filename-stem keyword match: the file's stem (case-insensitive) matches one of:
deploy,rollback,setup,onboard,audit,install,release,build,migrate,sync
- (a) Step-numbered sections: the file contains lines matching
-
Qualifying file (at least one marker matched):
-
(4a) Derive skill name: extract the filename stem; normalize to kebab-case (lowercase, spaces and underscores replaced with hyphens).
<stem>= normalized stem. -
(4b) Infer format type using the 4-signal heuristic (first match wins; precedence: anti-pattern > reference > procedural):
- If the source file contains a heading starting with
## Anti-patterns→anti-pattern - Else if the source file contains a heading starting with
## Patternsor## Examples→reference - Otherwise (step-numbered sections, process headings, trigger patterns, keyword stem, or no signals) →
procedural(default)
- If the source file contains a heading starting with
-
(4c) Idempotency guard: check whether
PROJECT_CLAUDE_DIR/skills/<stem>/SKILL.mdalready exists.- If it exists: record
<filename>.md — [already exists — not overwritten]. Skip to the next file; do NOT write anything. - If it does not exist: proceed to 4d.
- If it exists: record
-
(4d) Generate SKILL.md skeleton based on inferred format type. Create directory
PROJECT_CLAUDE_DIR/skills/<stem>/if absent. Write the appropriate skeleton toPROJECT_CLAUDE_DIR/skills/<stem>/SKILL.md:For
proceduralformat:--- name: <stem> description: > Scaffold description. Replace this text with what the skill does and when to trigger it. format: procedural --- # <stem> **Triggers**: Replace this scaffold text with the slash command and natural-language triggers. --- ## Process ### Step 1 — Replace with a concrete step name Replace this scaffold text with the first concrete action the skill should perform. --- ## Rules - Replace this scaffold rule with a real constraint or invariant.For
referenceformat:--- name: <stem> description: > Scaffold description. Replace this text with what the skill does and when to trigger it. format: reference --- # <stem> **Triggers**: Replace this scaffold text with the slash command and natural-language triggers. --- ## Patterns ### Pattern 1 — Replace with a concrete pattern name Replace this scaffold text with the pattern description. --- ## Rules - Replace this scaffold rule with a real constraint or invariant.For
anti-patternformat:--- name: <stem> description: > Scaffold description. Replace this text with what the skill does and when to trigger it. format: anti-pattern --- # <stem> **Triggers**: Replace this scaffold text with the slash command and natural-language triggers. --- ## Anti-patterns ### Anti-pattern 1 — Replace with a concrete anti-pattern name Replace this scaffold text with the anti-pattern description. --- ## Rules - Replace this scaffold rule with a real constraint or invariant. -
(4e) Record outcome:
<filename>.md → .claude/skills/<stem>/SKILL.md — scaffolded (format: <format>).
-
-
Non-qualifying file (no marker matched): Record:
<filename>.md — advisory only (no qualifying signals). Do NOT create or modify any file.
Invariant: Source files in
commands/are NEVER deleted, moved, or modified — regardless of scaffold outcome. The scaffold strategy writes only toPROJECT_CLAUDE_DIR/skills/<stem>/SKILL.md. No deletion prompt is ever issued for thecommands/category.
Pattern: docs/
- Match condition: Directory named
docs(case-insensitive) - Strategy:
copy— per.mdfile - Destination:
PROJECT_ROOT/ai-context/features/<name>.mdfor each*.mdfile at the immediatedocs/level
Copy procedure (runs when docs/ category is confirmed in Step 5.7):
- List all
.mdfiles at the immediatedocs/level only (no recursion). - Ensure
PROJECT_ROOT/ai-context/features/directory exists; create it if absent before copying. - For each
.mdfile:- Derive
<name>= filename including.mdextension. - Destination =
PROJECT_ROOT/ai-context/features/<name>.md. - If destination exists: record
<name> — skipped (destination exists). Do NOT overwrite. - If destination does not exist: copy source to destination; record
<name> — copied to ai-context/features/<name>.md.
- Derive
- Source files are NEVER deleted, moved, or modified.
Pattern: system/
- Match condition: Directory named
system(case-insensitive) - Strategy:
append— route by filename to appropriateai-context/file - Routing table:
architecture.md→PROJECT_ROOT/ai-context/architecture.mddatabase.md→PROJECT_ROOT/ai-context/stack.mdapi-overview.md→PROJECT_ROOT/ai-context/stack.md- All other files at the immediate
system/level → record as<filename> — no routing rule; skipped
Append procedure (runs when system/ category is confirmed in Step 5.7):
- List all files at the immediate
system/level only (no recursion). - For each file matched by the routing table:
- Destination = the mapped
ai-context/file. - If destination does not exist: create it with the appended content.
- Merge strategy: append the entire file content to the destination, preceded by the labeled separator:
<!-- appended from .claude/system/<filename> YYYY-MM-DD -->(ReplaceYYYY-MM-DDwith the current date at apply time.) - Record:
<filename> — appended to <destination> (separator added).
- Destination = the mapped
- Source files are NEVER deleted, moved, or modified.
Pattern: plans/
- Match condition: Directory named
plans(case-insensitive) - Strategy:
copy— route by active / archived status - Routing:
- Active plans →
PROJECT_ROOT/openspec/changes/<plan-name>/ - Archived plans →
PROJECT_ROOT/openspec/changes/archive/<plan-name>/
- Active plans →
Active vs. archived determination: The skill does NOT apply any heuristic to classify a plan item as active or archived. For each item at the immediate plans/ level, the skill MUST ask the user at apply time:
Is "<plan-name>" an active plan or an archived plan? (active/archived)
Copy procedure (runs when plans/ category is confirmed in Step 5.7):
- List all items at the immediate
plans/level only (no recursion). - For each item, prompt the user to classify it as active or archived (per item).
- Determine destination directory:
- Active →
PROJECT_ROOT/openspec/changes/<plan-name>/ - Archived →
PROJECT_ROOT/openspec/changes/archive/<plan-name>/
- Active →
- If destination directory already exists: record
<plan-name> — skipped (destination exists). Do NOT overwrite. - If destination directory does not exist: create the directory; copy the item's contents into it; record
<plan-name> — copied to <destination>. - Source files and directories are NEVER deleted, moved, or modified.
Pattern: requirements/
- Match condition: Directory named
requirements(case-insensitive) - Strategy:
scaffold— idempotent - Destination:
openspec/changes/<YYYY-MM-DD>-<slug>/proposal.md— one proposal stub per.mdfile at the immediaterequirements/level.<slug>is derived from the filename stem (filename without the.mdextension).<YYYY-MM-DD>is the current date at apply time.
Scaffold procedure (runs when requirements/ category is confirmed in Step 5.7):
-
List all
.mdfiles at the immediaterequirements/level only (no recursion into subdirectories). -
For each
.mdfile:-
Derive
<slug>= filename stem (case-preserved, e.g.auth-requirements.md→auth-requirements). -
Construct scaffold path:
PROJECT_ROOT/openspec/changes/<YYYY-MM-DD>-<slug>/proposal.md. -
If
proposal.mdalready exists at that path: record<slug> — scaffold skipped (proposal.md already exists). Do NOT overwrite. -
If
proposal.mddoes not exist: create the directoryopenspec/changes/<YYYY-MM-DD>-<slug>/and write the following minimal scaffold:# Proposal: <slug> ## Problem Statement <!-- Describe the problem to be solved. --> ## Proposed Solution <!-- Describe the proposed approach. --> ## Success Criteria - [ ] -
Record:
<slug> — scaffolded to openspec/changes/<date>-<slug>/proposal.md.
-
-
Source files are NEVER deleted, moved, or modified.
Pattern: sops/
- Match condition: Directory named
sops(case-insensitive) - Strategy:
user-choice— per file - Destinations:
- Option A: Append file content as a named section to
PROJECT_ROOT/ai-context/conventions.md. Section heading:## <stem>(filename stem). Ifai-context/conventions.mddoes not exist, create it. Append under labeled separator:<!-- appended from .claude/sops/<filename> YYYY-MM-DD -->. - Option B: Copy file to
PROJECT_ROOT/docs/sops/<filename>. Createdocs/sops/directory if absent. If destination already exists: record<filename> — skipped (destination exists). Do NOT overwrite.
- Option A: Append file content as a named section to
User-choice procedure (runs when sops/ category is confirmed in Step 5.7):
- List all
.mdfiles at the immediatesops/level only (no recursion). - Present the list to the user with both destination options.
- The user selects per file, or can use global shortcuts:
apply option A to all— applies Option A to all files insops/apply option B to all— applies Option B to all files insops/
- Execute the selection for each file according to the chosen option.
- Source files are NEVER deleted, moved, or modified.
Pattern: templates/
- Match condition: Directory named
templates(case-insensitive) - Strategy:
copy - Destination:
PROJECT_ROOT/docs/templates/<filename>— one copy per file at the immediatetemplates/level (no recursion into subdirectories oftemplates/).
Copy procedure (runs when templates/ category is confirmed in Step 5.7):
- List all files at the immediate
templates/level only (no recursion). - Ensure
PROJECT_ROOT/docs/templates/directory exists; create it if absent before copying. - For each file:
- Destination =
PROJECT_ROOT/docs/templates/<filename>. - If destination exists: record
<filename> — skipped (destination exists). Do NOT overwrite. - If destination does not exist: copy source to destination; record
<filename> — copied to docs/templates/<filename>.
- Destination =
- Source files are NEVER deleted, moved, or modified.
Pattern: project.md
-
Match condition: Root-level
.mdfile namedproject.md(case-insensitive match on the full filename). -
Strategy:
section-distribute -
Section routing heuristic: read the file's section headings and route each section to a destination using the following signal lists:
STACK_HEADING_SIGNALS = ["## Tech Stack", "## Stack", "## Dependencies", "## Tools"] ARCH_HEADING_SIGNALS = ["## Architecture", "## System Design", "## Overview"] ISSUES_HEADING_SIGNALS = ["## Known Issues", "## Issues", "## Gotchas", "## Limitations"]- A heading matching any entry in
STACK_HEADING_SIGNALS→ routes that section toai-context/stack.md - A heading matching any entry in
ARCH_HEADING_SIGNALS→ routes that section toai-context/architecture.md - A heading matching any entry in
ISSUES_HEADING_SIGNALS→ routes that section toai-context/known-issues.md - Headings matching no signal list are not routed and not appended to any file.
- A heading matching any entry in
Section-distribute procedure (runs when project.md category is confirmed in Step 5.7):
- Read the file's section headings.
- For each heading matched by a signal list, extract the section content (from the heading to the next same-level or higher heading).
- Per-section user confirmation: present each matched section's content to the user and request explicit confirmation before appending. Do NOT append any section that the user does not confirm.
- Append strategy: append each confirmed section to the destination file under the labeled separator:
<!-- appended from .claude/<filename> YYYY-MM-DD -->(Replace<filename>with the actual filename, e.g.project.md. ReplaceYYYY-MM-DDwith the current date.) If the destination file does not exist, create it with the appended content. - Source file is NEVER deleted or modified.
Pattern: readme.md
- Match condition: Root-level
.mdfile namedreadme.md(case-insensitive match on the full filename). - Strategy:
user-choice - Classification:
LEGACY_MIGRATION—readme.mdis NOT classified assection-distributeand is NOT subject to heading-signal routing. - Destinations:
- Option A: Append full file content to
PROJECT_ROOT/CLAUDE.mdunder the marker<!-- .claude/readme.md -->. CreateCLAUDE.mdif absent (unlikely but guarded). - Option B: Copy
readme.mdtoPROJECT_ROOT/docs/README-claude.md. Createdocs/directory if absent.
- Option A: Append full file content to
Idempotency guard: Before presenting options to the user, check whether PROJECT_ROOT/CLAUDE.md already contains the string <!-- .claude/readme.md -->.
- If the marker IS present → record
readme.md — already integrated (skipped)and skip this pattern entirely. Do NOT present options. - If the marker is NOT present → proceed to present Option A and Option B.
User-choice procedure (runs when readme.md category is confirmed in Step 5.7):
See Step 5.7.2b below for the full execution procedure.
Step 3c — Skills Audit
After Step 3b completes, perform a skills audit over the .claude/skills/ directory.
Skip condition: If PROJECT_CLAUDE_DIR/skills/ does not exist as a directory, skip this step entirely. Do not produce an error.
Initialize the findings list:
SKILL_AUDIT_FINDINGS = []
Scope-overlap detection — read the CLAUDE.md Skills Registry:
- Read
PROJECT_CLAUDE_DIR/CLAUDE.md. - Locate the Skills Registry section (look for the comment
<!-- Skills Registryor headings containingSkills Registry). - Extract all lines matching the pattern
~/.claude/skills/<name>/SKILL.md(where<name>is a non-empty path segment with no slashes). - Build
GLOBAL_REGISTRY_NAMES= set of<name>values extracted (case-sensitive stems).
If PROJECT_CLAUDE_DIR/CLAUDE.md does not exist or the Skills Registry section cannot be located, treat GLOBAL_REGISTRY_NAMES as an empty set (scope-overlap detection produces no findings, but other rules still run).
Detection loop:
Enumerate all immediate subdirectories of PROJECT_CLAUDE_DIR/skills/ (one level deep only — do not recurse).
For each subdirectory D:
Detection Rule 1 — scope_overlap (HIGH):
If D.name is present in GLOBAL_REGISTRY_NAMES (case-sensitive string equality):
SKILL_AUDIT_FINDINGS.append({
skill_name: D.name,
finding_type: "scope_overlap",
severity: "HIGH",
detail: "also referenced as ~/.claude/skills/" + D.name + "/ in CLAUDE.md Skills Registry"
})
Detection Rule 2 — broken_shell (MEDIUM):
If PROJECT_CLAUDE_DIR/skills/D.name/SKILL.md does NOT exist as a file:
SKILL_AUDIT_FINDINGS.append({
skill_name: D.name,
finding_type: "broken_shell",
severity: "MEDIUM",
detail: "no SKILL.md found in directory"
})
Detection Rule 3 — suspicious_name (LOW):
If D.name does NOT match the kebab-case convention — i.e., it contains at least one of:
- An uppercase letter (
A–Z) - A space character
- An underscore character (
_)
SKILL_AUDIT_FINDINGS.append({
skill_name: D.name,
finding_type: "suspicious_name",
severity: "LOW",
detail: "name does not follow kebab-case convention (contains spaces, uppercase letters, or underscores)"
})
Multiple findings per directory: all three rules are applied independently to each subdirectory. A single directory may produce multiple
SKILL_AUDIT_FINDINGSentries — one per rule that fires.
SKILL_AUDIT_FINDINGS entry structure:
Field Type Description skill_namestring The immediate subdirectory name under .claude/skills/finding_type"scope_overlap"|"broken_shell"|"suspicious_name"Which detection rule fired severity"HIGH"|"MEDIUM"|"LOW"Severity corresponding to finding type detailstring Human-readable explanation of the finding Findings are advisory only — this step NEVER modifies, deletes, or moves any file.
Step 4 — Build and present dry-run plan
Build the reorganization plan from the three categories above.
If MISSING_REQUIRED is empty AND UNEXPECTED is empty AND DOCUMENTATION_CANDIDATES is empty AND LEGACY_MIGRATIONS is empty:
Output:
No reorganization needed — .claude/ already matches the canonical SDD structure.
Proceed directly to Step 6 to write the report (no confirmation prompt needed).
Otherwise, display the plan in this format:
Reorganization Plan for: <PROJECT_CLAUDE_DIR>
─────────────────────────────────────────────
To be created (missing required items):
+ CLAUDE.md — stub file (5 section headings)
+ skills/ — empty directory
Documentation to migrate → ai-context/:
→ stack.md → ai-context/stack.md (copy only — source preserved)
→ notes.md → ai-context/notes.md (copy only — source preserved)
Note: individual files can be excluded before confirmation — list them as
exclusions when responding to the prompt below.
Legacy migrations (source files offered for deletion after successful migration):
~ commands/ — strategy: scaffold — active SKILL.md generation per qualifying .md file
Files to scaffold:
deploy.md → .claude/skills/deploy/ [format: procedural]
auth.md → [already exists — will skip]
misc.md — non-qualifying (no structured workflow detected)
(Source files in commands/ are NEVER deleted or modified.)
~ docs/ — strategy: copy — each .md file → ai-context/features/<name>.md
~ system/ — strategy: append — architecture.md → ai-context/architecture.md;
database.md + api-overview.md → ai-context/stack.md
~ plans/ — strategy: copy — active → openspec/changes/<name>/;
archived → openspec/changes/archive/<name>/
~ requirements/ — strategy: scaffold — openspec/changes/<date>-<slug>/proposal.md per .md file
~ sops/ — strategy: user-choice — Option A: ai-context/conventions.md section;
Option B: docs/sops/<filename>
~ templates/ — strategy: copy — each file → docs/templates/<filename>
~ project.md — strategy: section-distribute → ai-context/stack.md,
ai-context/architecture.md, ai-context/known-issues.md
~ readme.md — strategy: user-choice
Option A: append full content to CLAUDE.md (marker: <!-- .claude/readme.md -->)
Option B: copy to docs/README-claude.md
Note: each legacy migration category requires explicit per-category confirmation in Step 5.7
before any write occurs. Source files are offered for deletion after successful migration —
deletion requires explicit user confirmation. scaffold (commands/) and section-distribute
strategies are exempt from cleanup prompts. readme.md (user-choice) deletion requires explicit
confirmation after successful migration only.
Skills audit:
(Displayed only when SKILL_AUDIT_FINDINGS is non-empty and .claude/skills/ exists)
| Skill | Finding | Severity |
|-------|---------|----------|
| `react-19` | scope_overlap — also referenced as `~/.claude/skills/react-19/` | HIGH |
| `_draft-auth` | suspicious_name — name does not follow kebab-case convention | LOW |
| `my-broken-skill` | broken_shell — no SKILL.md found in directory | MEDIUM |
(When SKILL_AUDIT_FINDINGS is empty: "Skills audit: no issues detected.")
(When .claude/skills/ was absent: omit the Skills audit section entirely.)
Unexpected items (will be flagged, NOT deleted or moved):
! commands/ — not part of canonical SDD .claude/ structure (review manually)
Already correct:
✓ hooks/
✓ ai-context/
✓ openspec/
These items will NOT be deleted or moved — unexpected items receive a warning
comment in the report only.
Omit any category that has zero items (applies to all four categories).
Skills audit rendering rules (applies to the Skills audit: section in the plan):
- If
PROJECT_CLAUDE_DIR/skills/does NOT exist → omit theSkills audit:section entirely from the plan display. - If
PROJECT_CLAUDE_DIR/skills/exists ANDSKILL_AUDIT_FINDINGSis non-empty → render the table with one row per finding. - If
PROJECT_CLAUDE_DIR/skills/exists ANDSKILL_AUDIT_FINDINGSis empty → display:Skills audit: no issues detected.(no table).
After displaying the plan, prompt:
Apply this plan? (yes/no)
Wait for user input before proceeding.
- If the user responds with
yes,y,proceed, orapply(case-insensitive) → proceed to Step 5. - If the user responds with
no,n,cancel, orabort, or provides no answer → output:
Stop. Do not write any files (including the report).Reorganization cancelled. No changes were made.
Step 5 — Apply plan (strictly additive)
Apply ONLY the operations listed in the plan. No additional operations.
5.1 — Create missing skills/ directory:
If skills/ is in MISSING_REQUIRED:
- Create an empty directory at
PROJECT_CLAUDE_DIR/skills/. - Do NOT place any files inside it.
- Record:
skills/ — directory created.
5.2 — Create missing hooks/ directory:
If hooks/ is in MISSING_REQUIRED (hooks/ is optional, but if explicitly listed in plan):
- Create an empty directory at
PROJECT_CLAUDE_DIR/hooks/. - Record:
hooks/ — directory created.
5.3 — Create missing CLAUDE.md stub:
If CLAUDE.md is in MISSING_REQUIRED:
- Verify
PROJECT_CLAUDE_DIR/CLAUDE.mddoes NOT already exist (idempotency guard). If it already exists → skip this operation, record asCLAUDE.md — already exists (skipped). - Write the following minimal stub to
PROJECT_CLAUDE_DIR/CLAUDE.md:
# [Project Name] — Claude Configuration
## Tech Stack
<!-- Add your project tech stack here. -->
## Architecture
<!-- Describe the project architecture here. -->
## Unbreakable Rules
<!-- Add project-specific rules here. -->
## Plan Mode Rules
<!-- Add plan mode rules here. -->
## Skills Registry
<!-- List skills used by this project here.
Global skills: ~/.claude/skills/<name>/SKILL.md
Local skills: .claude/skills/<name>/SKILL.md
Run /project-setup for full initialization. -->
- Record:
CLAUDE.md — stub file created.
5.4 — Copy documentation candidates to ai-context/:
Process each file in DOCUMENTATION_CANDIDATES:
(a) Ensure PROJECT_ROOT/ai-context/ exists:
If the directory does not exist, create it before attempting any copy.
(b) For each file NOT excluded by the user:
- Check whether the destination (
PROJECT_ROOT/ai-context/<filename>.md) already exists.- If destination exists: do not write anything. Record:
<filename>.md — skipped (destination exists — review manually). Leave both source and destination untouched. - If destination does not exist: copy source to destination. After the copy, verify that the source file still exists at
PROJECT_CLAUDE_DIR/<filename>.md.- If source still exists → record:
<filename>.md — copied to ai-context/<filename>.md. - If source no longer exists after copy → record:
<filename>.md — failed — source missing after copyand do NOT mark as success.
- If source still exists → record:
- On any other copy failure: record
<filename>.md — failed — <error reason>and continue processing remaining candidates.
- If destination exists: do not write anything. Record:
(c) For each file excluded by the user:
- Do NOT copy or modify the file.
- Record:
<filename>.md — excluded by user.
Source preservation invariant: NEVER delete or modify the source file under any circumstance. The source file at PROJECT_CLAUDE_DIR/<filename>.md must exist and be unmodified after this step completes.
5.5 — Flag unexpected items:
For each item in UNEXPECTED:
- Do NOT touch the file or directory in any way.
- Record it as
<name> — unexpected item flagged in report (not modified).
5.6 — Acknowledge already-correct items:
For each item in PRESENT:
- No operation performed.
- Record it as
<name> — already correct (no change).
5.7 — Apply legacy migrations (per-category confirmation gates):
Process categories in strategy execution order: scaffold (commands/) → section-distribute (project.md) → user-choice (readme.md) → copy → append → scaffold (requirements/) → user-choice (sops/).
For each category in LEGACY_MIGRATIONS (grouped by strategy, processed in the order above):
- Present the full list of files in the category and their proposed destinations.
- Prompt:
Apply <category> migrations? (yes/no/all) - If the user responds
no: skip the category entirely; record<category> — skipped by user (no files written). Do NOT write any files for this category. - If the user responds
yesorall: apply the strategy for this category (see sub-steps below). Theallresponse also confirms all remaining unprocessed categories — no further per-category prompts are required for those.
5.7.1 — scaffold strategy (commands/):
-
List all
.mdfiles at the immediatecommands/level (no recursion into subdirectories). -
If no
.mdfiles are found at the immediate level: Output:commands/ — no .md files found at immediate level; nothing to scaffoldStop processing this category. -
For each
.mdfile found, apply the 4 qualifying markers (any one is sufficient to qualify):- (a) Step-numbered sections: the file contains lines matching
### Step N,- Step N, orN.where N is a number - (b) Trigger / invocation patterns: the file contains lines starting with
/command-nameor lines containing**Triggers**ortrigger: - (c) Process headings: the file contains a section heading that is exactly
## Process,## Steps,## How to, or## Instructions - (d) Filename-stem keyword match: the file's stem (case-insensitive) matches one of:
deploy,rollback,setup,onboard,audit,install,release,build,migrate,sync
- (a) Step-numbered sections: the file contains lines matching
-
Qualifying file (at least one marker matched):
-
(4a) Derive skill name: extract the filename stem; normalize to kebab-case (lowercase, spaces and underscores replaced with hyphens).
<stem>= normalized stem. -
(4b) Infer format type using the 4-signal heuristic (first match wins; precedence: anti-pattern > reference > procedural):
- If the source file contains a heading starting with
## Anti-patterns→anti-pattern - Else if the source file contains a heading starting with
## Patternsor## Examples→reference - Otherwise (step-numbered sections, process headings, trigger patterns, keyword stem, or no signals) →
procedural(default)
- If the source file contains a heading starting with
-
(4c) Idempotency guard: check whether
PROJECT_CLAUDE_DIR/skills/<stem>/SKILL.mdalready exists.- If it exists: record
<filename>.md — already exists (not overwritten). Review .claude/skills/<stem>/SKILL.md manually.Skip to the next file; do NOT write anything. - If it does not exist: proceed to 4d.
- If it exists: record
-
(4d) Generate SKILL.md skeleton based on inferred format type. Create directory
PROJECT_CLAUDE_DIR/skills/<stem>/if absent. Write the appropriate skeleton toPROJECT_CLAUDE_DIR/skills/<stem>/SKILL.md:For
proceduralformat:--- name: <stem> description: > <stem> — migrated from .claude/commands/<filename>.md format: procedural --- # <stem> > <stem> procedure. **Triggers**: <stem> --- ## Process <source file content copied here> --- ## Rules - <!-- Add rules and constraints here. -->For
referenceformat:--- name: <stem> description: > <stem> — migrated from .claude/commands/<filename>.md format: reference --- # <stem> > <stem> reference. **Triggers**: <stem> --- ## Patterns <source file content copied here> --- ## Rules - <!-- Add rules and constraints here. -->For
anti-patternformat:--- name: <stem> description: > <stem> — migrated from .claude/commands/<filename>.md format: anti-pattern --- # <stem> > <stem> anti-patterns. **Triggers**: <stem> --- ## Anti-patterns <source file content copied here> --- ## Rules - <!-- Add rules and constraints here. --> -
(4e) Record outcome:
<filename>.md — scaffolded to .claude/skills/<stem>/SKILL.md (format: <format>).
-
-
Non-qualifying file (no marker matched): Record:
<filename>.md — non-qualifying (no structured workflow detected). Recommend manual archival.Do NOT create or modify any file.
Invariant: Source files in
commands/are NEVER deleted, moved, or modified — regardless of scaffold outcome. No deletion prompt is ever issued for thecommands/category.
5.7.2 — section-distribute strategy (project.md):
- Read the file's section headings.
- For each heading, apply emoji normalization before comparing against any signal list:
- Strip leading Unicode emoji characters (including all Unicode emoji ranges and variation selectors) and any following whitespace from the heading text.
- Use the normalized form for all signal-list comparisons.
- The original heading text is preserved — the source file is NEVER modified.
- Any per-section confirmation prompt shown to the user MUST display the original heading text (including emoji prefix), not the normalized form.
- Map each heading (using normalized text) to a destination file using the signal lists:
STACK_HEADING_SIGNALS = ["## Tech Stack", "## Stack", "## Dependencies", "## Tools"]→ai-context/stack.mdARCH_HEADING_SIGNALS = ["## Architecture", "## System Design", "## Overview"]→ai-context/architecture.mdISSUES_HEADING_SIGNALS = ["## Known Issues", "## Issues", "## Gotchas", "## Limitations"]→ai-context/known-issues.md- Headings matching no signal list (even after normalization) are not routed.
- Per-section user confirmation: for each mapped section, present the section content to the user (with original heading text including any emoji) and request explicit confirmation before appending. Do NOT append any section the user does not confirm.
- Append strategy: append each confirmed section to the destination file under the labeled separator:
<!-- appended from .claude/<filename> YYYY-MM-DD -->(Replace<filename>with the actual filename, e.g.project.md. ReplaceYYYY-MM-DDwith the current date.) If the destination file does not exist, create it with the appended content. - Source file is NEVER deleted or modified.
- Advisory — zero matches: after processing all headings, if zero headings matched any signal list (even after emoji normalization), output:
Advisory: no headings in <filename> matched any signal list after emoji normalization — file content was not distributed. Recommend manual migration.(Replace<filename>with the actual filename.)
5.7.2b — user-choice strategy (readme.md):
This step runs only when readme.md is present in LEGACY_MIGRATIONS.
-
Idempotency guard: Check whether
PROJECT_ROOT/CLAUDE.mdalready contains the string<!-- .claude/readme.md -->.- If the marker IS present: record
readme.md — already integrated (skipped). Skip all remaining sub-steps. Do NOT present any options to the user. - If the marker is NOT present: proceed to step 2.
- If the marker IS present: record
-
Present the following prompt to the user:
readme.md migration — choose an option: Option A: Append full content to PROJECT_ROOT/CLAUDE.md (marker: <!-- .claude/readme.md --> will be added) Option B: Copy to PROJECT_ROOT/docs/README-claude.md Skip: leave readme.md in place (manual review recommended) -
If user selects Option A:
- Idempotency guard (double-check at write time): re-verify that
PROJECT_ROOT/CLAUDE.mddoes NOT already contain<!-- .claude/readme.md -->. If it does → recordreadme.md — already integrated (skipped)and stop. - Append the following block to
PROJECT_ROOT/CLAUDE.md:
(If<!-- .claude/readme.md --> <full content of readme.md>PROJECT_ROOT/CLAUDE.mddoes not exist, create it before appending.) - Record:
readme.md — appended to CLAUDE.md (Option A).
- Idempotency guard (double-check at write time): re-verify that
-
If user selects Option B:
- Ensure
PROJECT_ROOT/docs/directory exists; create it if absent. - Copy
readme.mdtoPROJECT_ROOT/docs/README-claude.md. - If
PROJECT_ROOT/docs/README-claude.mdalready exists: recordreadme.md — skipped (docs/README-claude.md already exists). Do NOT overwrite. - If it does not exist: copy and record
readme.md — copied to docs/README-claude.md (Option B).
- Ensure
-
If user skips: record
readme.md — skipped by user. Recommend manual review.Do NOT write any file. -
Source preservation: The source file
.claude/readme.mdis NEVER deleted or modified as part of this step. Cleanup follows the standard cleanup prompt flow only when the migration was successful (Option A or Option B applied) AND the user explicitly confirms cleanup. -
Cleanup prompt (only when migration was successful — outcome recorded as "appended" or "copied"):
Cleanup available for .claude/readme.md: Will be deleted (successfully migrated): readme.md Delete source file .claude/readme.md? (yes/no)- If user responds
yes: deletePROJECT_CLAUDE_DIR/readme.md. Record.claude/readme.md — deleted. - If user responds
no: recordreadme.md — cleanup declined by user.
- If user responds
Invariant: Source file
.claude/readme.mdis NEVER deleted unless the migration step was successful AND the user explicitly confirmed the cleanup prompt above.
5.7.3 — copy strategy (docs/ and templates/):
For docs/:
- List all
.mdfiles at the immediatedocs/level only (no recursion). - Ensure
PROJECT_ROOT/ai-context/features/directory exists; create it if absent before copying. - For each
.mdfile:- Destination =
PROJECT_ROOT/ai-context/features/<name>.md. - If destination exists: record
<name>.md — skipped (destination exists). Do NOT overwrite. - If destination does not exist: copy source to destination; record
<name>.md — copied to ai-context/features/<name>.md.
- Destination =
- Source files are NEVER deleted, moved, or modified.
For templates/:
- List all files at the immediate
templates/level only (no recursion). - Ensure
PROJECT_ROOT/docs/templates/directory exists; create it if absent before copying. - For each file:
- Destination =
PROJECT_ROOT/docs/templates/<filename>. - If destination exists: record
<filename> — skipped (destination exists). Do NOT overwrite. - If destination does not exist: copy source to destination; record
<filename> — copied to docs/templates/<filename>.
- Destination =
- Source files are NEVER deleted, moved, or modified.
5.7.3-cleanup — source file cleanup after copy strategy (docs/ and templates/):
For each category processed by 5.7.3 (docs/ and templates/):
- Guard — strategy eligibility: copy strategy is eligible for cleanup. Proceed.
- Guard — success count: count files with outcome "copied to ...". If count = 0 (all files were skipped or failed), skip cleanup for this category — do NOT present a prompt.
- Build lists:
WILL_DELETE= files whose outcome was "copied to ..." (successful migration)WILL_PRESERVE= files whose outcome was "skipped (destination exists)", "failed", or any non-success outcome
- Present both lists to the user:
Cleanup available for .claude/<category>/: Will be deleted (successfully migrated): <filename>, <filename>, ... Will be preserved (skipped — destination exists): <filename>, ... - Prompt:
Delete source files from .claude/<category>/? (yes/no) - If user responds
yes: delete each file inWILL_DELETEfrom its source path underPROJECT_CLAUDE_DIR/<category>/. Record each deletion as.claude/<category>/<filename> — deleted. Do NOT delete the parent directory. - If user responds
no: record<category>/ — cleanup declined by user. Do NOT delete any file.
Invariant: Only files in
WILL_DELETE(confirmed successful migration) may be deleted.WILL_PRESERVEfiles are NEVER deleted regardless of user input.
5.7.4 — append strategy (system/):
- List all files at the immediate
system/level only (no recursion). - Apply routing table:
architecture.md→PROJECT_ROOT/ai-context/architecture.mddatabase.md→PROJECT_ROOT/ai-context/stack.mdapi-overview.md→PROJECT_ROOT/ai-context/stack.md- All other files → record as
<filename> — no routing rule; skipped
- For each file matched by the routing table:
- If destination does not exist: create it with the appended content.
- Append block: append the entire file content to the destination, preceded by:
<!-- appended from .claude/system/<filename> YYYY-MM-DD -->(ReplaceYYYY-MM-DDwith the current date at apply time.) - Record:
<filename> — appended to <destination> (separator added).
- Source files are NEVER deleted, moved, or modified.
5.7.4-cleanup — source file cleanup after append strategy (system/):
- Guard — strategy eligibility: append strategy is eligible for cleanup. Proceed.
- Guard — success count: count files with outcome "appended to ...". If count = 0, skip cleanup — do NOT present a prompt.
- Build lists:
WILL_DELETE= files whose outcome was "appended to ... (separator added)"WILL_PRESERVE= files whose outcome was "no routing rule; skipped" or any non-success outcome
- Present both lists to the user:
Cleanup available for .claude/system/: Will be deleted (successfully appended): <filename>, ... Will be preserved (no routing rule or skipped): <filename>, ... - Prompt:
Delete source files from .claude/system/? (yes/no) - If user responds
yes: delete each file inWILL_DELETEfromPROJECT_CLAUDE_DIR/system/<filename>. Record each deletion as.claude/system/<filename> — deleted. Do NOT delete thesystem/directory itself. - If user responds
no: recordsystem/ — cleanup declined by user. Do NOT delete any file.
Invariant: Only files in
WILL_DELETE(confirmed successful append) may be deleted.WILL_PRESERVEfiles are NEVER deleted.
5.7.5 — scaffold strategy (requirements/):
-
List all
.mdfiles at the immediaterequirements/level only (no recursion). -
For each
.mdfile:-
Derive
<slug>= filename stem (filename without the.mdextension). -
Construct scaffold path:
PROJECT_ROOT/openspec/changes/<YYYY-MM-DD>-<slug>/proposal.md(use current date). -
If
proposal.mdalready exists at that path: record<slug> — scaffold skipped (proposal.md already exists). Do NOT overwrite. -
If
proposal.mddoes not exist: create the directoryopenspec/changes/<YYYY-MM-DD>-<slug>/and write the following minimal scaffold:# Proposal: <slug> ## Problem Statement <!-- Describe the problem to be solved. --> ## Proposed Solution <!-- Describe the proposed approach. --> ## Success Criteria - [ ] -
Record:
<slug> — scaffolded to openspec/changes/<date>-<slug>/proposal.md.
-
-
Source files are NEVER deleted, moved, or modified.
5.7.5-cleanup — source file cleanup after scaffold strategy (requirements/):
- Guard — strategy eligibility: scaffold strategy is eligible for cleanup. Proceed.
- Guard — success count: count files with outcome "scaffolded to ...". If count = 0, skip cleanup — do NOT present a prompt.
- Build lists:
WILL_DELETE= files whose outcome was "scaffolded to ..."WILL_PRESERVE= files whose outcome was "scaffold skipped (proposal.md already exists)" or any non-success outcome
- Present both lists to the user:
Cleanup available for .claude/requirements/: Will be deleted (successfully scaffolded): <filename>.md, ... Will be preserved (scaffold skipped — proposal already exists): <filename>.md, ... - Prompt:
Delete source files from .claude/requirements/? (yes/no) - If user responds
yes: delete each file inWILL_DELETEfromPROJECT_CLAUDE_DIR/requirements/<filename>. Record each deletion as.claude/requirements/<filename> — deleted. Do NOT delete therequirements/directory itself. - If user responds
no: recordrequirements/ — cleanup declined by user. Do NOT delete any file.
Invariant: Only files in
WILL_DELETE(confirmed successful scaffold) may be deleted.WILL_PRESERVEfiles are NEVER deleted.
5.7.6 — user-choice strategy (sops/):
- List all
.mdfiles at the immediatesops/level only (no recursion). - Present the list to the user with both destination options:
- Option A: Append file content as a named section (
## <stem>) toai-context/conventions.mdunder labeled separator<!-- appended from .claude/sops/<filename> YYYY-MM-DD -->; createai-context/conventions.mdif absent. - Option B: Copy file to
docs/sops/<filename>; createdocs/sops/directory if absent; skip if destination exists and record.
- Option A: Append file content as a named section (
- The user selects per file, or can use global shortcuts:
apply option A to all— applies Option A to all files insops/apply option B to all— applies Option B to all files insops/
- Execute the selection for each file according to the chosen option. Record each operation outcome.
- Source files are NEVER deleted, moved, or modified.
5.7.6-cleanup — source file cleanup after user-choice strategy (sops/):
- Guard — strategy eligibility: user-choice strategy is eligible for cleanup. Proceed.
- Guard — success count: count files with outcome "copied to ..." (Option B) or "appended to ..." (Option A). If count = 0, skip cleanup — do NOT present a prompt.
- Build lists:
WILL_DELETE= files whose outcome was "copied to ..." or "appended to ..."WILL_PRESERVE= files whose outcome was "skipped (destination exists)" or any non-success outcome
- Present both lists to the user:
Cleanup available for .claude/sops/: Will be deleted (successfully processed): <filename>.md, ... Will be preserved (skipped — destination exists): <filename>.md, ... - Prompt:
Delete source files from .claude/sops/? (yes/no) - If user responds
yes: delete each file inWILL_DELETEfromPROJECT_CLAUDE_DIR/sops/<filename>. Record each deletion as.claude/sops/<filename> — deleted. Do NOT delete thesops/directory itself. - If user responds
no: recordsops/ — cleanup declined by user. Do NOT delete any file.
Invariant: Only files in
WILL_DELETE(confirmed successful user-choice migration) may be deleted.WILL_PRESERVEfiles are NEVER deleted.
5.7.7 — copy strategy (plans/):
- List all items at the immediate
plans/level only (no recursion). - For each item, present it to the user and ask:
Is "<plan-name>" an active plan or an archived plan? (active/archived) - Determine destination directory:
- Active →
PROJECT_ROOT/openspec/changes/<plan-name>/ - Archived →
PROJECT_ROOT/openspec/changes/archive/<plan-name>/
- Active →
- If destination directory already exists: record
<plan-name> — skipped (destination exists). Do NOT overwrite. - If destination directory does not exist: create the directory; copy the item's contents into it; record
<plan-name> — copied to <destination>. - Source files and directories are NEVER deleted, moved, or modified.
5.7.7-cleanup — source file cleanup after copy strategy (plans/):
- Guard — strategy eligibility: copy strategy is eligible for cleanup. Proceed.
- Guard — success count: count items with outcome "copied to ...". If count = 0 (all items were skipped), skip cleanup — do NOT present a prompt.
- Build lists:
WILL_DELETE= items whose outcome was "copied to ..." (successful migration)WILL_PRESERVE= items whose outcome was "skipped (destination exists)" or any non-success outcome
- Present both lists to the user:
Cleanup available for .claude/plans/: Will be deleted (successfully migrated): <plan-name>, <plan-name>, ... Will be preserved (skipped — destination exists): <plan-name>, ... - Prompt:
Delete source files from .claude/plans/? (yes/no) - If user responds
yes: delete each item inWILL_DELETEfromPROJECT_CLAUDE_DIR/plans/<plan-name>. Record each deletion as.claude/plans/<plan-name> — deleted. Do NOT delete the parentplans/directory. - If user responds
no: recordplans/ — cleanup declined by user. Do NOT delete any file.
Invariant: Only items in
WILL_DELETE(confirmed successful migration) may be deleted.WILL_PRESERVEitems are NEVER deleted regardless of user input.
Step 6 — Write report
Write claude-organizer-report.md to PROJECT_CLAUDE_DIR. Overwrite any previous file.
Use this format:
# Claude Organizer Report
Run date: <YYYY-MM-DD>
Project root: <PROJECT_ROOT>
Target: <PROJECT_CLAUDE_DIR>
Summary: <N> item(s) created, <N> documentation file(s) copied, <N> legacy migration(s) applied, <N> unexpected item(s) flagged, <N> already correct
---
## Plan Executed
### Created
<!-- List items created, or state "Nothing to create — no required items were missing." -->
- `skills/` — empty directory created
- `CLAUDE.md` — stub file created with 5 section headings (Tech Stack, Architecture, Unbreakable Rules, Plan Mode Rules, Skills Registry)
> CLAUDE.md stub note: the file contains the 5 required section headings only.
> Populate this file with project-specific SDD configuration.
> Run /project-setup for full initialization.
### Documentation copied to ai-context/
<!-- Omit this subsection entirely when DOCUMENTATION_CANDIDATES was empty for the run. -->
<!-- List each candidate with its outcome: -->
- `stack.md` — copied to ai-context/stack.md
- `architecture.md` — skipped (destination exists — review manually)
- `notes.md` — excluded by user
### Legacy migrations
<!-- Omit this subsection entirely when LEGACY_MIGRATIONS was empty for the run. -->
<!-- List each legacy category processed with per-file outcome lines. -->
<!-- Valid outcome labels: applied, skipped, advisory, non-qualifying, user-skipped -->
**commands/** (strategy: scaffold):
- `deploy.md` — scaffolded to .claude/skills/deploy/SKILL.md (format: procedural)
- `auth.md` — already exists (not overwritten). Review .claude/skills/auth/SKILL.md manually.
- `misc.md` — non-qualifying (no structured workflow detected). Recommend manual archival.
**docs/** (strategy: copy):
- `auth.md` — copied to ai-context/features/auth.md
- `payments.md` — skipped (destination exists)
**system/** (strategy: append):
- `architecture.md` — appended to ai-context/architecture.md (separator added)
- `database.md` — appended to ai-context/stack.md (separator added)
**requirements/** (strategy: scaffold):
- `auth-requirements` — scaffolded to openspec/changes/2026-03-04-auth-requirements/proposal.md
**sops/** (strategy: user-choice):
- `deployment.md` — copied to docs/sops/deployment.md (Option B)
**templates/** (strategy: copy):
- `prd-template.md` — copied to docs/templates/prd-template.md
**project.md** (strategy: section-distribute):
- `## Tech Stack` section — appended to ai-context/stack.md
- `## Architecture` section — appended to ai-context/architecture.md
**readme.md** (strategy: user-choice):
<!-- Omit this block entirely when readme.md was absent from the project's .claude/ for the run. -->
<!-- One of the following outcome lines applies: -->
<!-- - readme.md — appended to CLAUDE.md (Option A) -->
<!-- - readme.md — copied to docs/README-claude.md (Option B) -->
<!-- - readme.md — skipped by user. Recommend manual review. -->
<!-- - readme.md — already integrated (skipped) -->
- `readme.md` — appended to CLAUDE.md (Option A)
<!-- Source-preservation footer — CONDITIONAL:
- When NO files were deleted: display the preservation note below.
- When files WERE deleted: omit the preservation note; the "Deleted from .claude/" subsection below serves as the deletion summary. -->
> All source files in legacy categories were preserved — no files were deleted or moved
### readme.md migration
<!-- Omit this subsection entirely when readme.md was absent from the project's .claude/ for the run. -->
<!-- One of the following outcome lines applies: -->
<!-- Valid outcome labels: appended to CLAUDE.md (Option A), copied to docs/README-claude.md (Option B), skipped by user, already integrated (skipped) -->
- `readme.md` — appended to CLAUDE.md (Option A)
### Commands scaffolded
<!-- Omit this subsection entirely when commands/ was absent from the project's .claude/ for the run. -->
<!-- List per-file scaffold outcomes using the labels below. -->
<!-- Valid outcome labels: scaffolded (format: <type>), [already exists — not overwritten], advisory only (no qualifying signals) -->
- `deploy.md` — scaffolded to .claude/skills/deploy/SKILL.md (format: procedural)
- `misc.md` — advisory only (no qualifying signals). Recommend manual archival.
- `auth.md` — [already exists — not overwritten]. Review .claude/skills/auth/SKILL.md manually.
### Skills audit
<!-- Omit this subsection entirely when .claude/skills/ was absent for the run. -->
<!-- When SKILL_AUDIT_FINDINGS is non-empty: render table below. -->
<!-- When SKILL_AUDIT_FINDINGS is empty: write "No issues detected in .claude/skills/." -->
| Skill | Finding | Severity |
| ----------------- | ----------------------------------------------------------------------------------------------------------------- | -------- |
| `react-19` | scope_overlap — also referenced as `~/.claude/skills/react-19/` | HIGH |
| `_draft-auth` | suspicious_name — name does not follow kebab-case convention (contains spaces, uppercase letters, or underscores) | LOW |
| `my-broken-skill` | broken_shell — no SKILL.md found in directory | MEDIUM |
> Findings are advisory only. No files were deleted or modified as part of skills audit.
> Remediate scope_overlap findings by removing the local copy or de-registering the global path from CLAUDE.md.
### Deleted from .claude/
<!-- Omit this subsection entirely when no cleanup prompts were presented during the run. -->
<!-- List each deleted file and each declined cleanup category. -->
- `.claude/docs/auth.md` — deleted
- `templates/ — cleanup declined by user`
### Unexpected items (not modified)
<!-- List unexpected items, or state "None." -->
- `commands/` — This item is not part of the canonical SDD .claude/ structure.
Review manually — it was NOT deleted or moved.
### Already correct
<!-- List items that were already present and expected, or state "None." -->
- `hooks/`
- `ai-context/`
- `openspec/`
---
## Recommended Next Steps
<!-- Conditional content — include only the applicable items: -->
1. Review the unexpected item(s) listed above — if intentional, document them in
.claude/CLAUDE.md; if not, remove them manually.
2. Populate the created stub files with project-specific content.
3. Review skipped documentation files — a file was skipped because its destination in
ai-context/ already exists. Compare source and destination manually and merge if needed.
4. Project .claude/ structure is now aligned with the canonical SDD layout.
<!-- Legacy migration conditional guidance — include only when the condition was true for this run: -->
<!-- If commands/ scaffold was run: -->
5. Review the commands/ scaffold outcomes above — check generated .claude/skills/<name>/SKILL.md
files and populate content. For files already existing (not overwritten), compare and merge manually.
<!-- If section-distribute applied to project.md or readme.md: -->
6. Review the distributed sections in the destination ai-context/ files — verify content is
correctly placed.
<!-- If append applied to system/: -->
7. Review the appended content in the ai-context/ destination file(s) — merge or deduplicate
manually if the appended section overlaps with existing content.
<!-- If scaffold produced proposals from requirements/: -->
8. Populate the scaffold proposals in openspec/changes/ before running /sdd-apply.
<!-- If sops/ was processed: -->
9. Verify the conventions section or docs/sops/ directory was correctly populated.
<!-- For a no-op run where nothing was missing: -->
<!-- No action required — .claude/ is already canonical. -->
---
> This file is a runtime artifact. Add `.claude/claude-organizer-report.md` to `.gitignore`
> to prevent accidental commits.
After writing the report, emit:
Report written to: <PROJECT_CLAUDE_DIR>/claude-organizer-report.md
Use the expanded absolute path (no tilde or relative segments).
Rules
-
Target is
PROJECT_ROOT/.claude/only — NEVER~/.claude/. This skill MUST NOT be invoked against the user-level runtime directory. If the resolvedPROJECT_CLAUDE_DIRmatches~/.claude/, the skill MUST exit immediately without changes. -
Apply step is strictly additive. Only
mkdirfor missing directories and write stubs for missing files. No delete, move, rename, or overwrite operations are permitted under any circumstances. Existing files and directories are never touched, regardless of content. -
User confirmation gate MUST NOT be skipped. The plan MUST be presented in full before any file write occurs. The skill MUST pause and wait for explicit user confirmation. If the user does not confirm affirmatively, the skill exits without writing any files (including the report).
-
Canonical expected item set MUST remain consistent with
claude-folder-auditCheck P8. The inline expected set defined in Step 3 is the single source of truth for this skill. Wheneverclaude-folder-auditCheck P8 expected items are updated, this skill's inline set MUST be updated in sync to prevent false-positive MEDIUM findings. -
Source files MUST NOT be deleted without BOTH conditions being true: (a) The file was successfully migrated (copied, appended, scaffolded, or user-choice applied) AND (b) the user explicitly confirmed the deletion prompt for that category. The
scaffoldstrategy forcommands/and thesection-distributestrategy (project.md) are permanently exempt from cleanup prompts — their source files are unconditionally preserved. Theuser-choicestrategy forreadme.mdoffers cleanup only after successful migration AND explicit user confirmation. Any file whose migration outcome was "skipped", "failed", or "excluded" MUST NOT be offered for deletion regardless of user input. -
Unexpected, unsupported, or ambiguous items remain advisory-first. If an observed item does not map cleanly to the canonical expected set, a supported legacy strategy, or a safe additive migration path, the organizer MUST report it for manual review instead of inventing a mutation.
-
Skills audit does not expand organizer mutation scope. Findings from
SKILL_AUDIT_FINDINGSare diagnostic only — even HIGH-severity findings such as scope overlap MUST NOT trigger automatic rewrites, deletions, or relocations under.claude/skills/. -
Cleanup deletion is a follow-up opt-in step, not core organizer behavior. The organizer's kernel ends at successful additive migration and report writing. Any deletion prompt is a post-migration choice applied only to explicitly eligible files after explicit user confirmation.