# Update Codebase Map

> Refresh an existing .claude/.codebase-info/ map after code changes. Use for stale codebase or architecture docs; use map-codebase to create one.

- Skill: `eigenwise/update-codebase-map` (Agent Skill)
- Install (CLI): `npx skillmds@latest add eigenwise/update-codebase-map`
- Raw SKILL.md: https://api.skillmd.com/api/skills/eigenwise/update-codebase-map/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: eigenwise (https://skillmd.com/u/eigenwise)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/eigenwise/update-codebase-map

---


# Update Codebase Map

Bring an existing map up to date with surgical edits : detect changes, touch only the affected
documents, keep everything internally consistent. This is a refresh, **not** a full rewrite.

## Prerequisite

A `.claude/.codebase-info/` directory with `INDEX.md` must already exist. If it doesn't, stop and
use the `map-codebase` skill to create the initial map.

## Process

The installed Mapper hook tells the main session to assess the map after code changes and invoke this
skill immediately when documentation work is warranted. A true no-op ends without editing the map or
refreshing state. This process does not wait for a separate user approval.

### Step 1 : Load current state

Read `.claude/.codebase-info/.map-state.json` to get `gitCommit`, `mappedAt`, and the list of
existing `documents`. Skim `INDEX.md` to recall what's already covered. (If `.map-state.json` is
missing : e.g. a map from an older version : fall back to the `mappedAt` date in `INDEX.md`, and
plan to write a fresh `.map-state.json` at the end.)

### Step 2 : Detect what changed

**Git repo (preferred : precise):** diff against the last-mapped commit.
```bash
git diff --stat <gitCommit>..HEAD          # which files changed, added, deleted
git log --oneline <gitCommit>..HEAD        # what the changes were about
git diff <gitCommit>..HEAD -- package.json pyproject.toml go.mod Cargo.toml composer.json Gemfile   # dependency churn (adjust to the project's manifests)
```

**No git, or no stored commit (fallback):** find source files modified since the map was written.
```bash
# files newer than the index (skip noise dirs)
find . -type f -newer .claude/.codebase-info/INDEX.md \
  -not -path '*/.git/*' -not -path '*/node_modules/*' -not -path '*/vendor/*' \
  -not -path '*/dist/*' -not -path '*/build/*' -not -path '*/target/*' -not -path '*/.venv/*'
```

### Step 2a : Decide whether to hand off

Do not ask the user whether to update the map, run this skill, or create a handoff. Decide using this
process, announce the applicable documentation-check outcome, and immediately perform the warranted
update or handoff without waiting for a reply.

A true no-op stays inline: report that no documented behavior, structure, interface, dependency, or
convention changed, then leave the map alone. Do not create a ticket merely to refresh timestamps or
state.

For an incremental refresh, work inline in the invoking session when the diff since the stored
`gitCommit` touches fewer than ~15 files across already-mapped areas and adds or removes no top-level
aspect. Apply Steps 3 through 5 directly. Do not create a ticket or dispatch an agent for this case.

Use an optional shared-tree artifact handoff for a full remap or large structural drift: a new subsystem,
a deleted service, or the first Dockerfile or datastore. For incremental work, stay inline. Inspect the
session tool roster before reading further. The handoff requires the native `Agent` tool plus Sidequest
`category_list`, `add`, `comment`, `dispatch`, and `pulse`. Do not probe the Sidequest CLI or dashboard.
Read the live `codebase-exploration` category and hand off only when it is enabled and its contract
permits one bounded documentation-artifact write while keeping project source read-only.

- When the tools are absent, continue inline without an error banner. Standalone Codebase Mapper does not
  require Sidequest.
- When Sidequest is present but the category is missing, disabled, or does not permit the bounded
  `.claude/.codebase-info/` artifact root, continue inline and say: `Sidequest is loaded, but its live taxonomy cannot accept map artifacts yet.`
- A read-only category with that artifact root is ready: shared-tree artifact mode permits the bounded
  map write and refuses every other project path.
- When it is ready, you may create one `codebase-exploration` artifact ticket with
  `files: [".claude/.codebase-info/"]` and this exact clause. Do it immediately without checking in with
  the user: `Artifact write carve-out: write only .claude/.codebase-info/**; all project source is read-only.`

The handoff ticket records the stored `gitCommit`, current `HEAD`, initial dirty-source status outside
`.claude/.codebase-info/`, and the current map document list. Its writer diffs from stored state through
the visible working tree, reassesses the warranted docs, preserves intentional manual map edits, touches
only affected docs, and replaces `.map-state.json` last. It must inspect the shared tree, verify every
cited path, skip generated/vendor/secret material, never touch `CLAUDE.md`, and never invoke
`map-codebase` or create nested mapping tickets. Include this lifecycle marker verbatim:

```text
Shared-tree artifact mode: leave the generated map as working-tree output; verify, comment, and close with done. Do not commit, submit, push, or edit source.
```

The invoking parent session verifies the generated paths and state after the writer closes, then commits the map if its flow permits.

Before dispatch, comment this reason:

```text
Shared-tree dispatch is required because the map must describe the current working tree, including intentional uncommitted source, and the generated .claude/.codebase-info/** files must remain visible to the invoking session.
```

Dispatch with `{ sharedTree: true }`, pass returned spawn fields to the native `Agent` unchanged, then
end the turn. Resume only on native completion, never by polling or a proxy waiter. Do not make
concurrent project edits while the writer owns the shared tree.

On completion, inspect the ticket evidence and verify `INDEX.md`, changed paths, and hashes without
redoing the codebase reading:

```text
node -e "const fs=require('node:fs'),c=require('node:crypto'),p='.claude/.codebase-info/',s=JSON.parse(fs.readFileSync(p+'.map-state.json','utf8'));if(!Array.isArray(s.documents))throw Error('documents');for(const n of new Set(['INDEX.md',...s.documents])){const b=fs.readFileSync(p+n,'utf8');if(!s.hashes||s.hashes[n]!==c.createHash('sha256').update(b.replace(/\r/g,'')).digest('hex'))throw Error(n)}"
```

Require cited-path checks, docs created/updated/removed, and confirmation that `CLAUDE.md` is untouched.
A writer whose source snapshot moves reconciles once or releases rather than certifying a mixed snapshot.
For a broad diff, use a `codebase-exploration` story with read-only area tickets and one dependent final
artifact writer. Area tickets report paths, symbols, entry points, and flows in their threads; never use
nested generic tasks.

For an add, dispatch, spawn, or executor failure, inspect `pulse` and the ticket thread. Retry once only
when a diagnosis changes the launch and no live claim remains. After a second failure, record the
evidence, ensure no writer owns the claim, validate or repair any partial map inline in this shared tree,
replace state last, and comment that the ticket completed through inline fallback. Give the user one short
line naming the failure and inline fallback.

### Step 3 : Re-assess the warranted doc set, then map changes to documents

An update is not only "edit the docs that exist." First **re-evaluate which documents this codebase
now warrants**, because the right set drifts as the project grows. The map should always carry the docs
that apply now, no more and no less:

- **A new aspect appeared → add its doc.** The project gained its first `Dockerfile`/`compose.yaml`, so
  create `docker.md` now even though the last map had none. First datastore → add `database.md`. First
  dependency manifest → add `dependencies.md`. A new major subsystem that no standard doc covers → add
  a custom doc (e.g. `ml-pipeline.md`, `realtime.md`), the same way `map-codebase` would. This is the
  common case the user cares about: you don't make `docker.md` until there's Docker, and once the code
  is dockerized, the next update is exactly when it should appear.
- **An aspect vanished → prune its doc.** A service, integration, or datastore was removed, so delete
  the now-empty doc and its `INDEX.md` row.

Then map the remaining changes onto the existing documents:

| If this changed… | Update… |
|------------------|---------|
| Directory layout (folders added/removed/renamed) | `directory-structure.md` |
| Components / services / module boundaries | `architecture.md`, `modules.md` |
| New/removed routes, CLI commands, jobs, handlers | `entry-points.md` |
| API contracts, events, queues, integrations | `communication.md` |
| Schema, migrations, new tables/collections | `database.md` |
| Dependency manifest (added/removed/upgraded) | `dependencies.md`, maybe `tech-landscape.md` |
| Design patterns, error handling, test setup, config | `patterns.md` |
| Linter/formatter config or naming conventions | `coding-style.md` |
| Container/compose setup | `docker.md` |
| Setup steps or common processes | `onboarding.md` |
| Project name/description, or any doc added/removed | `INDEX.md` |

Prioritize structural changes (new/removed entry points, components, infra, data model) over cosmetic
ones. Skip pure internal refactors that don't change any documented interface, layout, or convention.

### Step 4 : Apply targeted edits

For each affected document:
1. Read it.
2. Make focused edits : change only what's now different; don't rewrite the whole file.
3. Update its `*Last Updated: YYYY-MM-DD*` line to today's real date.

Then carry out the additions and removals you identified in Step 3:
- **New doc for an aspect that appeared:** create it from the matching template in
  `../map-codebase/references/document-templates.md` (or, for a non-standard aspect, follow the same
  shape), then add it to `INDEX.md` and to the `documents` list in state.
- **Prune a doc for an aspect that vanished:** delete the now-empty doc (and its `INDEX.md` row), or
  prune the stale sections from a shared doc. Remove orphaned references.

### Step 5 : Re-record state

After the final document edits, run the bundled state writer from the installed plugin:

```bash
node "${CLAUDE_PLUGIN_ROOT}/scripts/write-map-state.js" --project .
```

It discovers the current documents, records today's date and the current commit (or `null` outside a
git repo), hashes the final bytes, and atomically replaces `.map-state.json` last. A manual edit or
interrupted write can leave hashes stale; that is safe because hooks hash live files and treat the
manifest only as a consistency check.

Then summarize for the user: which docs you updated, created, or removed, and why. Outside shared-tree
artifact mode, commit the refreshed map unless the user explicitly says not to commit, and include
**`.map-state.json` alongside the edited docs**. An uncommitted manifest means every other checkout
sees stale hashes and re-flags docs that are actually current. If `git check-ignore
.claude/.codebase-info/INDEX.md` matches (a broad `.claude/*` rule), add `!.claude/.codebase-info/`
and `!.claude/.codebase-info/**` to `.gitignore` in the same commit; the ignore warning on `git add`
does not mean the map is local-only. If the user explicitly says not to commit, leave the verified map
changes and `.map-state.json` in the working tree and say plainly that they still need review or
committing.

## Guidelines

- **Surgical, not sweeping.** Targeted edits keep diffs reviewable and history meaningful.
- **Verify before writing.** Every path you add must exist; every path you remove must really be
  gone.
- **No churn for churn's sake.** If nothing meaningful changed, say so and leave the map and state
  untouched.
- **Never touch `CLAUDE.md`.** The plugin's hook handles loading; the map lives entirely in
  `.claude/.codebase-info/`. Leave `CLAUDE.md` (and `CLAUDE.local.md`) alone.

## Success criteria

- [ ] Changes since the last map detected (via stored commit, or mtime fallback)
- [ ] Warranted doc set re-assessed: docs added for aspects that appeared (e.g. Docker, a datastore),
      docs pruned for aspects that vanished
- [ ] Only affected documents edited; new areas documented; removed areas pruned
- [ ] `INDEX.md` reflects any added/removed docs
- [ ] `Last Updated` dates current on every touched doc
- [ ] `CLAUDE.md` left untouched
- [ ] `.map-state.json` rewritten with today's date, current commit, and document list
- [ ] Map changes committed including `.map-state.json` (or the user told plainly they still need
      committing)

