Skip to content
Back to skills

Project Consolidation

ASecurity

Safely consolidate drifted/duplicate project folders in the memex vault — cwd-fragment folders (e.g. `Apps-arena`, `GitHub-loom`), duplicate/split projects (one project's content scattered across two folders), and name-mismatch folders. Trigger on "consolidate project folders", "merge duplicate projects", "fix project detection drift", "deduplicate Apps-* folders", "clean up fragment folders", or after `memex check --folders` reports drift. Preserves observations + embeddings via `memex obs r...

  • 7 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 25, 2026
ai-agentspythongobashsqlgit

Works with

  • claude code
  • cli

Security analysis

A93/100
  • highPerforms destructive filesystem operations

Pro shows the line behind each finding and how to fix it

Scanned September 25, 2026

npx -y skills add linxule/memex-plugin --skill project-consolidation --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Project Consolidation?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Project Consolidation
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/linxule-project-consolidation-memex-plugin/badge)](https://www.skillsdirectory.com/skills/linxule-project-consolidation-memex-plugin)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: project-consolidation
description: Safely consolidate drifted/duplicate project folders in the memex vault — cwd-fragment folders (e.g. `Apps-arena`, `GitHub-loom`), duplicate/split projects (one project's content scattered across two folders), and name-mismatch folders. Trigger on "consolidate project folders", "merge duplicate projects", "fix project detection drift", "deduplicate Apps-* folders", "clean up fragment folders", or after `memex check --folders` reports drift. Preserves observations + embeddings via `memex obs reassign` (never naive `git mv` + rebuild, which cascade-deletes obs).
---

> Portable copy of `skills/project-consolidation/SKILL.md` for Codex and Kimi Code, generated by `scripts/portable_plugin.py` (do not edit here). Needs the `memex` CLI on PATH. Claude Code names (the Task/Agent tool, `/memex:save`, hooks) map to your host's equivalents.

# Project-Folder Consolidation

Drifted project folders happen when session→project detection produced a
non-canonical name: a cwd-path fragment (`Apps-arena` instead of `arena`), or a
project split across folders (content under both `personal-website` and
`linxule_com`). The detection bugs that caused this were fixed in v0.15.5/v0.15.6
(`detect_project` via true session `cwd` + restored `project_mappings`), so **no
new drift forms** — this skill cleans up existing debt.

## The cardinal rule

**Never run `memex obs reassign` on a folder until you have confirmed it is a
duplicate or strict subset of the canonical target.** A wrong merge collapses two
distinct projects. And **never** consolidate via `git mv` + `memex index rebuild`
— the incremental rebuild detects the old paths as deleted and **cascade-deletes
the observations and their embeddings**. `obs reassign` is the only safe primitive
(it `UPDATE`s `doc_path` in `observations` + `chunks`, preserving embeddings).

## Step 1 — Audit

```bash
memex check --folders            # human report: high-confidence drift + review list
memex check --folders --json     # machine-readable, for planning
```

- **High-confidence drift** = cwd-fragment-shaped names, or content ⊆ another folder. Safe to act on after confirming duplication.
- **Review (lower confidence)** = `name≠canonical` / canonical collisions. The git remote or a memo's recorded `cwd` can legitimately differ from a deliberately-chosen folder name (e.g. a real project whose folder ≠ its repo name). **Verify manually; do not auto-act.**

## Step 2 — Confirm duplication (before touching anything)

Pick the canonical target — prefer the folder that already holds the most
observations and matches `detect_project` / `project_mappings`. Then prove the
source is redundant:

```bash
# Memo/transcript filename overlap (a strict subset is a clean duplicate):
comm -23 <(ls projects/<from>/memos/ | sort) <(ls projects/<to>/memos/ | sort)        # files UNIQUE to <from>
comm -23 <(ls projects/<from>/transcripts/ | sed 's/\.\(md\|jsonl\)$//' | sort -u) \
         <(ls projects/<to>/transcripts/ | sed 's/\.\(md\|jsonl\)$//' | sort -u)
# If a memo exists in both, diff it — often only the `project:` frontmatter line differs:
diff projects/<from>/memos/<file>.md projects/<to>/memos/<file>.md
```

If everything in `<from>` is already in `<to>` (only `project:` differs), `<from>`
is a pure duplicate → delete it (Step 4b). If `<from>` has UNIQUE content → migrate
it (Step 3). Auto-memory under a fragment is almost always a re-syncable duplicate
(source of truth is `~/.claude/projects/*/memory/`); transcripts/memos with no
canonical twin are unique and must be moved, not deleted.

## Step 3 — Migrate unique content (preserves obs + embeddings)

```bash
# Record the invariant BEFORE:
memex obs stats          # or: total-obs count — must be unchanged at the end

# 3a. Move files on disk (git mv for tracked memos/_project; mv for gitignored transcripts):
mkdir -p projects/<to>/memos projects/<to>/transcripts
git mv projects/<from>/memos/*.md projects/<to>/memos/
mv    projects/<from>/transcripts/*  projects/<to>/transcripts/    2>/dev/null

# 3b. Update the project: frontmatter on moved memos:
for m in projects/<to>/memos/<moved>*.md; do
  sed -i.bak 's/^project: <from>$/project: <to>/' "$m" && rm -f "$m.bak"
done

# 3c. Reassign obs + chunks by SUBPREFIX (avoids the _project.md collision):
memex obs reassign --from-prefix "projects/<from>/memos/"       --to-prefix "projects/<to>/memos/"          # dry-run
memex obs reassign --from-prefix "projects/<from>/memos/"       --to-prefix "projects/<to>/memos/" --apply
memex obs reassign --from-prefix "projects/<from>/transcripts/" --to-prefix "projects/<to>/transcripts/" --apply
```

Reassign reports `obs_updated` / `chunks_updated` and rolls back on a UNIQUE
collision (same `doc_path` already at the target — a sign the file is a true
duplicate, not a unique migration; delete the source copy instead).

## Step 4 — Finish

```bash
# 4a. Archive the fragment _project.md as a redirect stub (audit trail), OR remove it
#     if the canonical _project.md is authoritative.
# 4b. Remove the now-empty / pure-duplicate fragment folder:
rm -rf projects/<from>
# 4c. Incremental rebuild (no-op on moved content since disk paths now match the index):
memex index rebuild --incremental
```

## Step 5 — Verify the invariant + prevent recurrence

```bash
memex check --folders        # the consolidated folder should be gone
memex obs stats              # TOTAL observations unchanged from Step 3 (the invariant)
```

- If total obs **dropped**, a cascade-delete happened — restore from git/backup and re-do via `obs reassign`, not `git mv`+rebuild.
- For a project whose cwd should always map to a specific name, pin it: add `"<cwd-substring>": "<canonical>"` to `~/.memex/config.json` → `project_mappings` (now honored in CLI as of v0.15.5). Verify each pin resolves: `PYTHONPATH=src uv run python -c 'from pathlib import Path; from memex.scripts.utils import detect_project; print(detect_project(Path("<cwd>")))'` from the memex repo.
- **A pin only affects sessions archived after it exists.** 2026-09-23: 12 fleet-worker folders had been archived on 09-06, two days before the `/private/tmp/ncs-` pin went in on 09-08 — the pin was right and the drift sat there anyway. After adding a pin, re-run `memex check --folders` and consolidate anything that pre-dates it.

## Recurring drift classes (what to look for)

- **Fleet workers in scratch cwds** — `entrypoint: sdk-cli` transcripts from `/private/tmp/<x>/<model>`, `/private/var/folders/…/T/<probe>`: the folder is named after the cwd leaf (`codex`, `gemini`, `tiny`, `workspace`, `fleet`). The folder name tells you nothing; recover the true cwd from the archived JSONL: `for j in projects/<f>/transcripts/*.jsonl; do grep -m1 -o '"cwd":"[^"]*"' "$j"; done | sort | uniq -c`.
- **Subfolders of a repo that didn't exist yet** — sessions from `teaching/<course>/materials` before `teaching/` was a git repo fell back to the leaf folder name; once the repo exists, detection resolves the parent. Pin the parent path so it holds either way.
- **Redirect stubs vs removal**: keep an archived redirect stub (`status: archived` + `redirect_to:`) for names a person might search for (`materials`, `skema-ai-pm`); remove the auto-generated stub for generic worker names (`codex`, `gemini`, `kimi`) — as project names they'd shadow real concepts.

## Ad-hoc SQL gotcha

When counting rows per folder by hand, **don't use `LIKE 'projects/<folder>/%'`**: SQLite `LIKE` is case-insensitive and `_` is a single-character wildcard, so `projects/Research_Calls/%` also matched every `projects/research-calls/` row (2026-09-23: reported 97 obs for a folder that had 0). Use an exact prefix: `WHERE substr(doc_path, 1, length('projects/<folder>/')) = 'projects/<folder>/'`. `memex obs reassign` itself compares prefixes literally and is safe.

## When to stop and ask

- The "review" (lower-confidence) findings — `name≠canonical` without content overlap — are usually **legitimate distinct projects**, not drift. Confirm with the user before merging.
- Two folders with substantial obs on **both** sides and only partial overlap = a genuine split needing human judgment on the canonical home, not a mechanical reassign.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.