---
name: maintain-filemap
description: >
  Use whenever the directory shape of a Lossless pseudomonorepo (or any
  child repo) changes — a new top-level directory is added, a submodule
  is mounted or unmounted, a major subsystem is renamed — or on a
  weekly cadence, or before any release that would land on GitHub, to
  regenerate the `FILEMAP.md` at each affected repo's root so
  collaborators see the current shape without cloning. Triggers when the
  user mentions "filemap", "tree", "directory layout", "repo overview",
  "what does this repo even contain", "new collaborator joining"; also
  when the agent itself proposes adding/removing a top-level dir or a
  submodule, because that's exactly the moment the discipline matters.
---

# maintain-filemap · Loop

> **When the directory shape changes, regenerate the map.** The committed `FILEMAP.md` at each repo root is the artifact a new collaborator opens first.

## What this loop does

Keeps a `FILEMAP.md` at the root of each Lossless repo current with the actual on-disk tree. Each `FILEMAP.md` has two parts:

1. **A curator preface** — hand-authored prose explaining what each top-level directory IS (purpose, ownership, conventions). Edited rarely (only when the meaning of a directory changes, not when its contents do).
2. **A generated tree** — produced by `tree -L 3` with a curated ignore set, spliced between `<!-- TREE-START -->` and `<!-- TREE-END -->` sentinels in a fenced code block. Regenerated by the loop's script every time the discipline fires.

Why both: a raw `tree` dump is useful but doesn't tell a newcomer *what they're looking at*. The curator preface is what makes the file legible; the generated tree is what makes it accurate.

## When this loop fires

Three triggers:

| Trigger | Cadence | How it fires |
|---|---|---|
| Directory-shape change | as-it-happens | Pre-commit hook, OR manually as part of the commit that changes shape |
| Weekly cadence | every Monday | Manual or cron; produces a no-op commit if nothing changed |
| Pre-release | before each `main`/`master` ship | Manual; bundled into the release commit |

The hook is optional but recommended. Without it, the discipline lives in the agent's working memory: "Did I just add `corpus/`? → regen FILEMAP."

## What changes is a "directory-shape change"

Triggers the loop:

- A new top-level directory was added (`mkdir context-v/loops/`)
- A submodule was mounted or unmounted (`.gitmodules` changed)
- A major subsystem was renamed (`apps/dididecks-shell/` → `apps/deck-shell/`)
- A top-level file like `CLAUDE.md` or `pnpm-workspace.yaml` was added
- A new client-site landed under `client-sites/`

Does NOT trigger the loop:

- A new file under an existing directory (e.g., adding `context-v/plans/Some-Plan.md`)
- A small refactor that doesn't change directory names
- A typo fix, dependency bump, or doc edit
- Adding a new variant under an existing client-site's `src/pages/scroll/{deck}/`

Rule of thumb: **if the change makes the FILEMAP's depth-3 view different, run the loop**.

## The recipe

```bash
# From the repo root
bash context-v/loops/maintain-filemap/scripts/regen-filemap.sh
```

The script:

1. `cd` to the repo root (via `git rev-parse --show-toplevel`)
2. Runs `tree -L 3 -I '<curated-ignore-pattern>' --noreport --dirsfirst`
3. Reads the current `FILEMAP.md`
4. Splices the new tree between `<!-- TREE-START -->` and `<!-- TREE-END -->` markers, preserving everything else
5. Writes back to `FILEMAP.md`
6. Reports git diff status; if changed, suggests `git add FILEMAP.md` for the next commit

The ignore pattern is the load-bearing knob — see `scripts/regen-filemap.sh` for the canonical set (`node_modules`, `.git`, `.astro`, `dist`, `.vercel`, `.output`, `cache`, `*.lock`, `.DS_Store`, `public`). Edit only when a new "noise" directory consistently appears across repos.

## The artifact

A `FILEMAP.md` at every repo root that participates. Per the pseudomonorepos discipline, every level of the tree has its own:

| Repo level | FILEMAP carries |
|---|---|
| Parent pseudomonorepo (`dididecks-ai/`) | Tree of `apps/`, `client-sites/` (submodule mount points + one level deep), `context-v/`, `changelog/`, `corpus/`, `splash/`, `data/` if present |
| Client-site (`client-sites/<client>/`) | Tree of the client's `src/`, `data/`, `db/`, `corpus/`, `context-v/`, `public/` |
| Shell submodule etc. | Each carries its own |

The PARENT's `FILEMAP.md` does NOT try to deeply enumerate submodule contents. It stops at the submodule mount + the submodule's own top-level dirs (depth 3 from parent ≈ depth 1 within submodule). For deeper detail, the reader follows the submodule's own `FILEMAP.md`.

## Detection — how to tell the loop is overdue

Two signals:

1. **Run the script.** If `git diff FILEMAP.md` is non-empty after running, the committed map is stale. Trivial to catch.
2. **Eyeball test.** If you `ls` the repo root and see a directory that's not in `FILEMAP.md`, the loop is overdue.

A future enhancement: a CI check that runs the script and fails the build if `git diff --quiet FILEMAP.md` would fail. Today it's local-discipline; promote to CI when a collaborator misses the discipline twice.

## Composition with other skills

| Companion skill | When it fires alongside this loop |
|---|---|
| [`git-conventions`](../../agent-skills/git-conventions/SKILL.md) | Always — the FILEMAP regen commit follows the standard `chore(filemap): regenerate after <change>` header pattern |
| [`changelog-conventions`](../../agent-skills/changelog-conventions/SKILL.md) | Usually no — a filemap regen alone doesn't warrant a changelog entry; the underlying change (new submodule, etc.) might |
| [`pseudomonorepos`](../../agent-skills/pseudomonorepos/SKILL.md) | When the change touches submodule mounts — the pseudomonorepos branch-alignment + relocation rules govern, and the FILEMAP regen is one part of the cleanup |
| [`context-vigilance`](../../agent-skills/context-vigilance/SKILL.md) | When the change is to `context-v/` itself — the loop regenerates the map; context-vigilance governs the contents of the map |

## Anti-patterns

- **Don't auto-commit FILEMAP.md from a hook.** The regen should stage the file but let the human approve. Auto-commits churn git history with no-op commits when the tree didn't actually change.
- **Don't autogenerate the curator preface.** The preface is what makes the file legible; an LLM-generated "this directory contains files" preface is worse than no preface at all.
- **Don't try to render submodule contents deeply in the parent.** Submodules carry their own FILEMAP. Parent stops at depth 3 and links into children.
- **Don't ignore the ignore set.** Generated `dist/` directories, `node_modules/`, and `.lock` files in the tree are noise that makes the map unreadable. The curated ignore pattern is load-bearing.

## See also

- [`scripts/regen-filemap.sh`](./scripts/regen-filemap.sh) — the recipe
- Each repo's `FILEMAP.md` — the artifact this loop maintains
- Parent loops README: [`../README.md`](../README.md)
- Companion skills under `context-v/agent-skills/`
