rebuild-index
Rebuild manifest.json for any artifact storage type. Scans directories and regenerates from scratch.
Files1
View on GitHubSKILL.mdskills/rebuild-index/SKILL.md
GitHubRebuild Index
Rebuild manifest.json for one or all artifact storage types by scanning directories and extracting metadata from state files.
Usage
/rebuild-index work # Rebuild work manifest
/rebuild-index brainstorms # Rebuild brainstorms manifest
/rebuild-index proposals # Rebuild proposals manifest
/rebuild-index refactoring # Rebuild refactoring manifest
/rebuild-index product-knowledge # Rebuild product knowledge manifest
/rebuild-index requirements # Delegates to /rebuild-requirements-index
/rebuild-index tasks # Rebuild the task store index (via tasks.sh)
/rebuild-index all # Rebuild all manifests
When to Use
- Manifest missing or corrupted
- After manual changes to artifact directories
- After cleanup or archival operations
- Periodic maintenance
- As a safety net when manifests fall out of sync
Context
Arguments: $ARGUMENTS
Configuration
Read .claude/configuration.yml for all artifact paths:
# Source resolve-config: marketplace installs get ${CLAUDE_PLUGIN_ROOT} substituted
# inline before bash runs; legacy local copies fall back to ~/.claude. If neither
# path resolves, fail loudly rather than letting resolve_artifact be undefined.
if [ -f "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh" ]; then
source "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh"
elif [ -f "$HOME/.claude/shared/resolve-config.sh" ]; then
source "$HOME/.claude/shared/resolve-config.sh"
else
echo "ERROR: resolve-config.sh not found — reinstall the nexus plugin: /plugin install nexus@claude-skills" >&2
exit 1
fi
IFS='|' read -r WORK_DIR WORK_TYPE <<< "$(resolve_artifact_typed work work)"
IFS='|' read -r BRAINSTORM_DIR BRAIN_TYPE <<< "$(resolve_artifact_typed brainstorms brainstorm)"
IFS='|' read -r PROPOSALS_DIR PROP_TYPE <<< "$(resolve_artifact_typed proposals proposals)"
IFS='|' read -r REFACTOR_DIR REFAC_TYPE <<< "$(resolve_artifact_typed refactoring work/refactoring-sessions)"
IFS='|' read -r REQUIREMENTS_DIR REQ_TYPE <<< "$(resolve_artifact_typed requirements requirements)"
IFS='|' read -r PRODUCT_DIR PROD_TYPE <<< "$(resolve_artifact_typed product-knowledge .)"
Process
Step 1: Parse Argument
Parse $ARGUMENTS to determine which artifact type(s) to rebuild.
Valid arguments: work, brainstorms, proposals, refactoring, product-knowledge, requirements, tasks, all
If no argument or invalid argument:
Error: Artifact type required.
Usage:
/rebuild-index work
/rebuild-index brainstorms
/rebuild-index proposals
/rebuild-index refactoring
/rebuild-index product-knowledge
/rebuild-index requirements
/rebuild-index tasks
/rebuild-index all
See `${CLAUDE_PLUGIN_ROOT}/shared/manifest-schema.md` for manifest schema details.
Step 2: Sync Git Locations
For any artifact directory whose storage type is git, sync before scanning
(loop over the four rebuild-eligible artifacts here — requirements and
product-knowledge are synced by their own delegated skill/agent):
# Re-derived here: shell state does not survive between Bash tool calls, so the
# paths and types the Configuration block resolved are empty in this one. Empty
# is not loud — "$_type" would never equal "git", every location would be
# skipped as if none were git-backed, and the rebuild below would then scan
# whatever was last pulled.
if [ -f "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh" ]; then
source "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh"
elif [ -f "$HOME/.claude/shared/resolve-config.sh" ]; then
source "$HOME/.claude/shared/resolve-config.sh"
else
echo "ERROR: resolve-config.sh not found — reinstall the nexus plugin: /plugin install nexus@claude-skills" >&2
exit 1
fi
IFS='|' read -r WORK_DIR WORK_TYPE <<< "$(resolve_artifact_typed work work)"
IFS='|' read -r BRAINSTORM_DIR BRAIN_TYPE <<< "$(resolve_artifact_typed brainstorms brainstorm)"
IFS='|' read -r PROPOSALS_DIR PROP_TYPE <<< "$(resolve_artifact_typed proposals proposals)"
IFS='|' read -r REFACTOR_DIR REFAC_TYPE <<< "$(resolve_artifact_typed refactoring work/refactoring-sessions)"
for pair in "work:$WORK_TYPE:$WORK_DIR" "brainstorms:$BRAIN_TYPE:$BRAINSTORM_DIR" \
"proposals:$PROP_TYPE:$PROPOSALS_DIR" "refactoring:$REFAC_TYPE:$REFACTOR_DIR"; do
IFS=':' read -r _artifact _type _dir <<< "$pair"
if [[ "$_type" == "git" && -d "$_dir" ]]; then
( cd "$_dir" && git pull --quiet )
fi
done
Step 3: Execute Rebuild(s)
For all, run each artifact type sequentially (or report results for each). For a single type, run just that one.
Special cases:
requirements→ Delegate to/rebuild-requirements-indexskillproduct-knowledge→ Delegate toproduct-expertagenttasks→ Delegate toshared/tasks/tasks.sh(see Rebuild: Tasks). Step 2's git sync and Step 3.5's commit do not apply: the task store is never git-backed — it lives in the project, or in a shared directory outside every repository (global mode), and neither is synced or committed.
Rebuild: Work
Path: $WORK_DIR
- Back up existing
${WORK_DIR}/manifest.jsontomanifest.json.backup.{TIMESTAMP} - Scan subdirectories of
$WORK_DIR - For each subdirectory, read
state.jsonand check thetypefield to detect work type:"implementation"→ type:implementation"proposal"→ type:proposal"epic"→ type:epic"requirements"→ type:requirements
- Extract metadata from the state file:
identifier: from state file or directory nametitle: from state filestatus: from state filecreated_at,updated_at: from state filecurrent_phase: derive from state file status fieldsprogress: derive from chunks or stagesbranch: from state file branches sectiontags: empty array (not tracked in state files)
- Build manifest with
artifact_type: "work" - Write to
${WORK_DIR}/manifest.json
Skip directories: manifest.json, manifest.json.backup.*, any file (non-directory)
Rebuild: Brainstorms
Path: $BRAINSTORM_DIR
- Back up existing manifest
- Scan subdirectories of
$BRAINSTORM_DIR - For each subdirectory, prefer
state.jsonas the source of truth for session fields — a brainstorm is a resumable session, and a rebuild that drops its status makes completed and promoted sessions look resumable again:slug:state.json.slug, else directory nametitle:state.json.title, else first heading inbrainstorm-summary.mdorapproaches.md, else slugstatus:state.json.status. Ifstate.jsonis missing or has no status, derive it —promotedwhenpromoted_tois set,completedwhenbrainstorm-summary.mdexists, otherwisein_progress. Never emit a null status.created_at:state.json.created_at, else earliest file mtimeupdated_at:state.json.updated_at, else latest file mtimecurrent_phase: last key instate.json.phasesmarkedcompleted, elseunknownpromoted_to:state.json.promoted_to, elsenullselected_approach:state.json.selected_approach, else extract frombrainstorm-summary.mdif it existsalternatives_count: count approach sections inapproaches.mdif existstags: preserve from the backed-up manifest entry if present, else empty arraypath:"{slug}/"(required by the schema)
- Build manifest with
artifact_type: "brainstorms" - Write to
${BRAINSTORM_DIR}/manifest.json
Legacy sessions. Brainstorms created before brainstorms became their own
artifact still sit under $WORK_DIR/{slug}/ and are indexed in the work
manifest with type: "brainstorm". /rebuild-index brainstorms scans
$BRAINSTORM_DIR only — it does not migrate them, and /rebuild-index work
will keep re-indexing them where they are. That is intentional: rebuilds
reindex, they never move data.
Rebuild: Proposals
Path: $PROPOSALS_DIR
- Back up existing manifest
- Scan subdirectories of
$PROPOSALS_DIR - For each subdirectory:
name: directory nametitle: extract from first heading inproposal-final.mdor latestproposal*.mdstatus:implementedifsrc/exists,finalifproposal-final.mdexists, elsedraftcreated_at: earliest file modification timeupdated_at: latest file modification timeiterations: count ofproposal*.mdfilestags: empty array
- Build manifest with
artifact_type: "proposals" - Write to
${PROPOSALS_DIR}/manifest.json
Rebuild: Refactoring
Path: $REFACTOR_DIR
- Back up existing manifest
- Scan subdirectories of
$REFACTOR_DIR - For each subdirectory with
session-state.json:session_name: from state file or directory nametitle: fromtarget.scopein state file, or directory namestatus: from state filecreated_at,updated_at: from state filefiles_affected: count fromtarget.filesarray in state fileprogress: derive fromprogress.completed/progress.completed + progress.pendingin state filetags: empty array
- Build manifest with
artifact_type: "refactoring" - Write to
${REFACTOR_DIR}/manifest.json
Rebuild: Product Knowledge
Path: $PRODUCT_DIR
Delegate to product-expert agent:
Task(product-expert, "Build a fresh manifest.json for the product knowledge base.
Knowledge base path: ${PRODUCT_DIR}
Process:
1. Scan all .md files recursively in the knowledge base
2. For each file:
- Extract title from first heading (or use filename)
- Determine category from parent directory name
- Extract tags from content (look for tags/keywords sections, or infer from headings)
- Create a one-line summary from the first paragraph
3. Build categories and tags frequency maps
4. Write manifest.json to ${PRODUCT_DIR}/manifest.json
Use the manifest schema from ${CLAUDE_PLUGIN_ROOT}/shared/manifest-schema.md (artifact_type: product-knowledge).
Include the extra 'categories' and 'tags' top-level fields.
")
product-expert only writes manifest.json — it has no git steps. If the
product-knowledge location is type: git, commit and push the rebuilt manifest
here (owner of the rebuild), otherwise it sits uncommitted and the next KB
git pull conflicts with it. Skip when $PROD_TYPE != git. Follows the
sanctioned KB-write pattern
(${CLAUDE_PLUGIN_ROOT}/shared/kb-write-pattern.md) —
cd in, push with the two logged bypasses, no record-audit.sh:
# Re-derived here: shell state does not survive between Bash tool calls, so the
# pair the Configuration block resolved is empty in this one — and an empty
# "$PROD_TYPE" fails the `git` test, leaving the manifest this step just wrote
# uncommitted, which is the exact conflict the paragraph above describes.
if [ -f "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh" ]; then
source "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh"
elif [ -f "$HOME/.claude/shared/resolve-config.sh" ]; then
source "$HOME/.claude/shared/resolve-config.sh"
else
echo "ERROR: resolve-config.sh not found — reinstall the nexus plugin: /plugin install nexus@claude-skills" >&2
exit 1
fi
# STRICT, not the advisory resolver, because what this gates is a WRITE — and
# not an ordinary one: the push below drops branch protection and the audit gate
# together. The advisory resolver answers "where would this live", and for an
# artifact nobody configured it answers `$WORKSPACE_ROOT/.claude`, inheriting the
# TYPE of whatever location it fell back to. Point `local` at a git location and
# `product-knowledge` at nothing, and the advisory pair comes back
# `<project>/.claude|git` — the test below passes and the bypassed push lands in
# the project's own repository. Strict refuses instead of fabricating (rc 3 here)
# and returns the same PATH|TYPE pair, so this is a swap, not a redesign.
if _RESOLVED=$(resolve_artifact_strict product-knowledge .); then
IFS='|' read -r PRODUCT_DIR PROD_TYPE <<< "$_RESOLVED"
else
echo "product-knowledge is not configured for storage — the rebuilt manifest stays local, uncommitted" >&2
PRODUCT_DIR=""; PROD_TYPE=""
fi
if [[ "$PROD_TYPE" == "git" && -d "$PRODUCT_DIR" ]]; then
(
cd "$PRODUCT_DIR"
git add manifest.json
if ! git diff --cached --quiet; then
# Explicit credential scan — the single-call form misses the hook's
# automatic one, and the product-knowledge manifest embeds first-paragraph
# excerpts from user docs (see Step 3.5 note).
if ! "${CLAUDE_PLUGIN_ROOT}/hooks/credential-scan.sh" manifest.json >&2; then
echo "WARN: credential finding in product-knowledge manifest.json — skipping its KB push" >&2
else
default_branch=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##')
[ -z "$default_branch" ] && default_branch=$(timeout 10 git ls-remote --symref origin HEAD 2>/dev/null \
| awk '/^ref:/ {sub("refs/heads/", "", $(2)); print $(2); exit}')
default_branch="${default_branch:-master}"
git commit -m "Rebuild product-knowledge manifest"
NEXUS_KB_WRITE=1 SECURITY_AUDITOR_BYPASS=1 git push origin -- "$default_branch"
fi
fi
)
fi
(The single-call caveat from Step 3.5 applies — branch protection and the audit gate are intentionally skipped for this KB push; the credential scan is run explicitly above rather than dropped.)
Rebuild: Requirements
Delegate entirely to the existing /rebuild-requirements-index skill:
The requirements knowledge base uses its own index.json format with richer metadata.
Delegating to /rebuild-requirements-index...
Trigger the /rebuild-requirements-index skill.
Rebuild: Tasks
The task store has one owner, shared/tasks/tasks.sh, and this target only asks
it to rebuild. Do not resolve the tasks path here, scan its files, back up or
write its manifest.json: the script resolves the store with its own write
gating — it refuses a git-backed, overlapping or broken tasks entry and writes
nothing — and applies archive-wins, which a second scan here could disagree with.
bash "${CLAUDE_PLUGIN_ROOT}/shared/tasks/tasks.sh" --op rebuild
- Exit
0: reportopen(tasks in the rebuilt index) andrepaired(leftover open copies of tasks that were already archived, now removed).note: "no task store yet"means there was nothing to rebuild and nothing was created. - Exit
20: the store's location was refused. Show the message unchanged — it names the reason — and report the target asRefused, not rebuilt. - Exit
30: show the message and reportFailed.
Step 3.5: Commit Git-Backed Manifests
After writing manifest.json for Work, Brainstorms, Proposals, or
Refactoring, commit and push it if that artifact's storage location is
type: git — otherwise the rebuilt manifest sits uncommitted locally and
the next git pull on that repo conflicts with it. This follows the
sanctioned KB-write pattern
(${CLAUDE_PLUGIN_ROOT}/shared/kb-write-pattern.md):
cd into the artifact directory (never git -C), and push with
NEXUS_KB_WRITE=1 SECURITY_AUDITOR_BYPASS=1 (both logged) rather than a
mechanical record-audit.sh rubber-stamp.
# Re-derived here, for the same reason Step 2 re-derives them: shell state does
# not survive between Bash tool calls. Empty values would make "$_type" never
# equal "git", so a rebuilt manifest in a git-backed location would silently go
# uncommitted — which is precisely the state this step exists to prevent.
if [ -f "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh" ]; then
source "${CLAUDE_PLUGIN_ROOT}/shared/resolve-config.sh"
elif [ -f "$HOME/.claude/shared/resolve-config.sh" ]; then
source "$HOME/.claude/shared/resolve-config.sh"
else
echo "ERROR: resolve-config.sh not found — reinstall the nexus plugin: /plugin install nexus@claude-skills" >&2
exit 1
fi
# STRICT here, unlike Step 2. Step 2 pulls; this pushes, with branch protection
# and the audit gate both dropped. For an artifact nobody configured, the
# advisory resolver fabricates a path under the project and inherits the fallback
# location's type — so `local: {type: git}` plus an unconfigured `brainstorms`
# makes the loop below push the project's own repository. Strict refuses rather
# than guessing; an artifact it refuses is skipped, not written to.
_pairs=()
for _art in work:work brainstorms:brainstorm proposals:proposals refactoring:work/refactoring-sessions; do
IFS=':' read -r _name _subdir <<< "$_art"
if _RESOLVED=$(resolve_artifact_strict "$_name" "$_subdir"); then
IFS='|' read -r _p _t <<< "$_RESOLVED"
_pairs+=("$_name:$_t:$_p")
else
echo "$_name is not configured for storage — its rebuilt manifest stays local, uncommitted" >&2
fi
done
for pair in "${_pairs[@]}"; do
IFS=':' read -r _artifact _type _dir <<< "$pair"
if [[ "$_type" == "git" && -d "$_dir" ]]; then
(
cd "$_dir"
git add manifest.json
if ! git diff --cached --quiet; then
# The single-call loop misses git-mutation-guard.sh's automatic
# credential scan (see note below), so run it EXPLICITLY on the
# manifest — its summary/title fields carry freeform excerpts from
# user/agent docs and could contain a pasted secret. Skip the push on a
# finding rather than committing it.
if ! "${CLAUDE_PLUGIN_ROOT}/hooks/credential-scan.sh" manifest.json >&2; then
echo "WARN: credential finding in ${_artifact} manifest.json — skipping its KB push" >&2
else
default_branch=$(git symbolic-ref --short refs/remotes/origin/HEAD 2>/dev/null | sed 's#^origin/##')
[ -z "$default_branch" ] && default_branch=$(timeout 10 git ls-remote --symref origin HEAD 2>/dev/null \
| awk '/^ref:/ {sub("refs/heads/", "", $(2)); print $(2); exit}')
default_branch="${default_branch:-master}"
git commit -m "Rebuild ${_artifact} manifest"
NEXUS_KB_WRITE=1 SECURITY_AUDITOR_BYPASS=1 git push origin -- "$default_branch"
fi
fi
)
fi
done
Note on the single-call loop. Because this loop runs as one Bash tool call, the input string begins with
for, sogit-mutation-guard.sh's anchored regexes (^\s*git\s+commit,^\s*git\s+push) match nothing — the innergit commit/git pushare invisible to the guard, so all three of its checks (branch protection, credential scan, audit gate) are skipped. Branch protection and the audit gate are intentionally bypassed for KB writes; the credential scan is not something to drop — manifest summary/title fields embed freeform excerpts from user/agent docs — so it is run explicitly viacredential-scan.shbefore each commit above. ⚠️ If an artifact location is ever misconfigured totype: gitpointing at the project repo, this loop would still push there with branch protection and the audit gate skipped — the explicit scan only covers credentials. Keep KB locations pointed at real KB repos. For any interactive or user-content KB write, use the separate-Bash-call form in the shared pattern doc so the guard runs in full.
Requirements manifests are committed by their own delegated skill
(/rebuild-requirements-index). The product-knowledge manifest is committed by
the Rebuild: Product Knowledge step above (it is not committed by
product-expert, which only writes the manifest) — do not duplicate either
here.
Step 4: Report Results
For each artifact type rebuilt, report:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Index Rebuilt: {artifact_type}
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Path: {artifact_dir}
Items found: {count}
Backup: manifest.json.backup.{timestamp}
Items:
- {item_1_key}: {title} ({status})
- {item_2_key}: {title} ({status})
...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
For all, show a summary table:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Index Rebuild Complete
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Artifact Items Status
──────────────────────────────────────────────
Work 3 Rebuilt
Brainstorms 1 Rebuilt
Proposals 2 Rebuilt
Refactoring 0 Empty (no sessions)
Product Knowledge 8 Rebuilt (via agent)
Requirements 5 Rebuilt (via /rebuild-requirements-index)
Tasks 4 Rebuilt (via tasks.sh)
Total: 23 items indexed across 7 artifact types.
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Error Handling
Artifact directory doesn't exist:
⚠ {artifact_type}: Directory not found: {path}
Skipping — no items to index.
No items found:
{artifact_type}: 0 items found in {path}
Created empty manifest.json.
Corrupt existing manifest:
⚠ {artifact_type}: Existing manifest.json is invalid JSON
Backed up to: manifest.json.corrupt.{timestamp}
Building fresh manifest from directory scan.
Agent delegation failure (product-knowledge):
⚠ product-knowledge: Agent failed to build manifest
Error: {error_message}
Options:
[r] Retry agent
[s] Skip product-knowledge
[a] Abort
Use AskUserQuestion for selection.
See Also
- Manifest Schema Reference — Schema details and update patterns
/rebuild-requirements-index— Requirements-specific index rebuild/load-context— Uses manifests for fast listing and lookup/resume-work— Uses work manifest to find incomplete work