Skip to content

Branches, Overlays & Freshness

Three freshness layers: default-branch index, auto-overlay for dirty files, registered overlays for long-lived branches

Prism's index is built from the default branch of each connected repo. When you work on a feature branch, the CLI layers your local state on top of that index automatically so reads stay accurate. This guide explains the three layers — default-branch index, auto-overlay for working-tree dirty files, and registered overlays for long-lived feature branches — and how to read the freshness fields that every response carries.

When to read this

  • You started a feature branch and want to know what prism search is actually searching.
  • You see resolved_overlay_branch in a tool response and want to understand what it means.
  • You're considering prism branch create and want to know whether your branch is long-lived enough to justify it.
  • A teammate pushed a commit to your overlay branch and you want to know how stale the index is.
  • You hit an overlay_recommended_for hint and want to know what the CLI is asking you to do.

How the CLI keeps your answers fresh

Every Prism read call (search, find-refs, def, body, outline, module-map, prepare-edit) consults three layers, in order of authority:

  1. Default-branch index. The Gateway keeps an AST-chunked, BM25-+-vector-indexed snapshot of the repo's default branch, refreshed by the three-tier ingestion pipeline. This is the baseline every query starts from.
  2. Auto-overlay (working-tree dirty files). On every read, the CLI runs git status and git diff to collect files you've changed since HEAD or since your overlay baseline. The contents are attached to the request as an _overlay payload so the Gateway can re-parse them on the fly.
  3. Registered overlay (long-lived branch). If your current branch is itself registered as an overlay — or descends from one — the Gateway uses chunks indexed against that overlay's HEAD as the primary source, with auto-overlay layered on top for anything you've changed since the overlay was last indexed.

Layer 1 is always present. Layer 2 is automatic — --auto-overlay is on by default, no flag required. Layer 3 only activates if prism branch create has been run for a relevant branch.

The result: most of the time you don't think about overlays at all. The CLI handles them, and your responses contain enough metadata (resolved_overlay_branch, overlay_consumed, indexed_at) to verify what happened.

When to register an overlay (the >1 week heuristic)

For short-lived branches — anything that merges within a few days — don't bother with prism branch create. The default-branch index plus auto-overlay covers you. The trade-off only flips for long-lived branches because registering an overlay costs a full clone-+-index pass (minutes, sometimes longer for large repos) and ongoing storage in the Console's database.

The decision rule:

Branch lifetime Recommendation Why
< 1 week Don't register. Default + auto-overlay is enough. Overlay registration cost (clone + index) exceeds the value over a few days of edits.
1–2 weeks, small change set Optional. Register if you notice search misses on branch-only symbols. Auto-overlay only attaches files you've touched in this session; symbols added by teammates on the branch won't appear in search.
> 1 week, or many commits, or shared with teammates Register. Search, find-refs, and module-map should reflect the branch's real shape — not just your local diffs.
Integration branch (multiple sub-branches off it) Register. Sub-branches resolve to the parent overlay via ancestry walk — one registration covers all the sub-branches.

Auto-overlay handles your unpushed files. A registered overlay handles the whole branch's diverged state, including commits from teammates, files deleted on the branch, and renames.

prism branch create and prism branch delete

Register an overlay while the branch is checked out:

prism branch create feature/auth-refactor

The Gateway clones the branch, runs the full ingestion pipeline (chunk → embed → describe → PageRank), and writes the overlay rows distinguished by a branch column in prism.code_chunks. The Console dashboard shows the overlay's status and indexed_at timestamp once it lands.

When the branch is merged or abandoned, delete it:

prism branch delete feature/auth-refactor

The handler removes overlay chunks and any tombstones (records of files deleted on the overlay) in the same transaction, so a re-registered same-name branch starts clean.

You can list active overlays for the current repo with:

prism branch list

Sub-branch behavior (ancestry walk)

A long integration branch can have many sub-branches off it. You don't register an overlay per sub-branch — the CLI walks Git ancestry to find the nearest registered overlay automatically.

Algorithm (the CLI runs this on every read):

  1. Detect the current branch. If it's itself a registered overlay, use it.
  2. Otherwise, fetch the repo's overlay list from the Console API.
  3. For each active overlay, try git merge-base --is-ancestor <overlay-ref> HEAD. The fallback chain is origin/<overlay-branch> → local refs/heads/<overlay-branch> → the overlay's recorded HEAD SHA. First success wins.
  4. If multiple overlays are ancestors of HEAD, pick the one with the smallest commit distance.
  5. Return that overlay name (or None if nothing qualifies).

Worked example: integration overlay feature/voice-v2-gemini-live is registered. You branch feature/voice-v2-extension-mute off it for a small extension. Running prism search "mute control flow" from the sub-branch resolves to the integration overlay automatically — you get the integration's indexed chunks, plus an auto-overlay payload carrying the sub-branch's committed-but-not-on-integration files and any uncommitted edits.

Resolution failures collapse to None (no overlay used) rather than raising — read commands stay green even in detached-HEAD, shallow-clone, or missing-remote situations. Run prism doctor to see which branch resolved and why.

Overlay-aware read tools

All 7 MCP read tools are overlay-aware by default:

Tool Notes
search_code Overlay chunks blended into the four-way RRF fusion; tombstones filter out files deleted on the overlay.
find_references Re-parses overlay-payload file content at query time — references in your unpushed code show up correctly.
get_symbol_definition Looks up the symbol in overlay chunks first, then default-branch.
get_symbol_body Returns overlay version of the source if a chunk exists; falls back to default.
outline Lists symbols from overlay-side chunks for overlay-modified files.
module_map PageRank entries for the overlay reflect the overlay's import graph.
prepare_edit Pulls source + callers + nearby tests from the overlay; pagerank carve-outs still read default for ranking signals.

Response payload fields

Every overlay-aware response carries:

  • resolved_overlay_branch (string | null, always present) — the branch the Gateway actually used in SQL. null means no overlay (default-branch-only result). This field closes the loop: you can see whether your branch was honored without inferring it from result content.
  • _overlay (object) — what the CLI sent: the resolved branch name, the HEAD SHA, and the dirty-/diff-file payload. Returned alongside the request data so you can audit what was attached.
  • overlay_consumed (bool) — true if the tool actually re-parsed overlay payload content; false if it only ran against the indexed snapshot. Use this to distinguish "the overlay was sent but the tool didn't need it" from "no overlay was attached".
  • overlay_files_applied (list of paths) — sorted file paths the tool read from the overlay payload. Empty list when the tool didn't consume.
  • overlay_recommended_for (list of paths) — paths that appear in the result set but were missing from the overlay payload. The CLI auto-retries the call once with those files attached.
  • next_actions (list) — hints from the Gateway. The overlay-specific hint fires when indexed_at is more than 24 hours old (suggesting prism branch refresh <name>).

See the FEAT-006 spec for the full envelope contract.

Overrides (--branch, --no-overlay, --fetch-overlay)

Default behavior is the right answer almost always. When it isn't, three flags are available on every read command:

Flag Effect
(none) Auto-resolve overlay via ancestry walk; attach diff + dirty files as auto-overlay.
--branch <name> Pin the query to a specific registered overlay. The branch must already be registered — passing an unregistered branch name triggers a structured branch_unsupported_for_this_tool envelope.
--no-overlay Suppress both the branch resolution and the overlay payload — pure default-branch view. Useful for sanity-checking what landed on main versus what the branch has.
--fetch-overlay Run git fetch --depth=50 origin <overlay-branch> before resolution. Helps when your local ref is behind a freshly-pushed overlay HEAD.
--no-fetch-overlay Suppress a fetch enabled in .prism/config.

--branch and --no-overlay are mutually exclusive. Passing both is a usage error — the CLI errors out client-side and the Gateway rejects the combination server-side with conflicting_overlay_args (HTTP 400) as defense in depth.

Per-repo defaults live in <git-root>/.prism/config:

[overlay]
fetch_overlay = true   # equivalent to passing --fetch-overlay on every read

Missing file or missing keys are non-errors. CLI flags override the config per-invocation.

Staleness signals

Every response carries two freshness fields you can read directly:

  • indexed_at — UTC timestamp of the last time the index used to serve this request was built. For default-branch reads, this is when ingestion last ran. For overlay reads, this is when the overlay was registered or last refreshed.
  • index_age_seconds — convenience field: now - indexed_at in seconds.

Rules of thumb:

  • index_age_seconds > 3600 on a default-branch query, and you haven't just connected the repo → the tier-3 webhook may be lagging. Recent collaborator pushes might not be indexed yet. Check the Console dashboard or trigger a reindex.
  • indexed_at > 24h on an overlay query → the Gateway emits a next_actions hint suggesting prism branch refresh <name>. Teammates may have pushed to the overlay branch since you registered it. Your local edits are still covered by auto-overlay; remote staleness is fixed by the refresh.
  • overlay_consumed: false when you expected true → either no overlay attached (check _overlay), or the tool didn't need to re-parse payload content for this query. Combine with prism doctor to confirm resolution.

Known gap: no head_sha column

PR-4 of FEAT-006 shipped without a head_sha column on the branch_overlays row. The diff baseline used by the CLI is origin/<overlay-branch>, not the SHA the overlay was indexed against.

The practical consequence: a force-push that rewrites the overlay's HEAD can drift the auto-overlay diff set. The CLI will compute the diff between your HEAD and the new origin/<overlay-branch>, which may skip files the original index covered or include files it shouldn't.

The mitigation today:

  • If a force-push has rewritten the overlay, run prism branch delete <name> followed by prism branch create <name> to rebuild from the new HEAD. Cheaper than living with drift.
  • The Gateway team will add the head_sha column when a force-push incident occurs or when registered overlay count exceeds ~5. Until then, treat force-pushes on overlay branches as a "refresh required" event.

See the CLAUDE.md branch-overlay section for ownership boundaries.

prism doctor overlay section

prism doctor (the CLI's environment check) includes an overlay section that reports:

  • Current branch — what git rev-parse --abbrev-ref HEAD says.
  • Resolved overlay branch — what resolve_overlay_branch returned, with a reason: exact_match, ancestor_distance=N, or none.
  • Diff file count and estimated payload bytes — how many files the auto-overlay would attach, and how close to the truncation cap.
  • Shallow-clone warning — if git rev-parse --is-shallow-repository is true, resolution will silently no-op; the warning surfaces it.
  • Stale-overlay warning — if origin/<branch> is ahead of the indexed HEAD, the resolved overlay is out of date.

By default, prism doctor runs git fetch --depth=50 origin <overlay-branch> to detect staleness accurately — this changes doctor's traditional read-only stance. Opt out with --no-fetch.

Run prism doctor whenever an overlay's behavior surprises you. It's the single command that tells you what the CLI sees.

FAQ

Q: Should I create an overlay for a 3-day branch?

A: No. Auto-overlay (the default) already attaches your working-tree dirty files to every read, and the default-branch index covers everything else. Registering an overlay costs a full clone-+-index pass; it only pays off for branches that live more than ~1 week, or branches that diverge significantly from main, or integration branches with sub-branches. See When to register an overlay.

Q: I'm on a sub-branch of a registered overlay. Do I need to register the sub-branch too?

A: No. The CLI walks Git ancestry on every read and finds the nearest registered overlay automatically. Your sub-branch's committed-but-not-on-integration files are picked up via the diff-overlay payload on top. See Sub-branch behavior.

Q: What does resolved_overlay_branch: null mean?

A: The Gateway served the query from the default-branch index only — no registered overlay was applied. Common reasons: (1) you're on the default branch, (2) no overlay is registered for any ancestor of your HEAD, (3) you passed --no-overlay, or (4) you're in a detached-HEAD / shallow-clone state where resolution failed. Your auto-overlay (working-tree dirty files) may still have been attached; check overlay_consumed and overlay_files_applied.

Q: How do I know if my overlay is stale?

A: Look at indexed_at in any response: if it's >24h old, the Gateway adds a next_actions hint suggesting prism branch refresh <name>. Or run prism doctor — its overlay section actively fetches origin/<overlay-branch> and compares it to the indexed HEAD, surfacing drift directly. See Staleness signals.

Q: What happens if my teammate force-pushes to the overlay branch?

A: The CLI will compute the auto-overlay diff against the new origin/<overlay-branch>, which can drift from what the index was built against (there's no head_sha column on the overlay record yet — see Known gap). The fix is prism branch delete <name> followed by prism branch create <name> to rebuild from the new HEAD.

Q: Can I pin a query to a registered overlay I'm not checked out on?

A: Yes. Pass --branch <name> on any read command. The branch must be registered as an overlay — passing an unregistered branch name returns a structured branch_unsupported_for_this_tool envelope. --branch and --no-overlay are mutually exclusive.

Q: Why is overlay_consumed: false when I clearly have dirty files?

A: Today, only find_references re-parses overlay content at query time. The other tools (search, def, body, outline, module_map, prepare_edit) acknowledge the overlay payload (overlay_files_applied is populated) but run against the indexed snapshot. The overlay_consumed: false flag is explicit so you can detect this case and fall back to a direct Read of the file you just edited if needed. Tier-2 (broader overlay consumption) is in flight.