review-with-untracked · git:20260622.0d6a088 · 2026-06-22 · sha256 60c4b7c8851e5413
review-with-untracked git:20260622.0d6a088A
Immutable. This exact content is served forever at /api/v1/blob/60c4b7c8851e5413.
---
name: review-with-untracked
description: Temporarily visualize untracked new files into the git diff so a chain of diff-deriving review callees can see them, then restore the files to untracked. Runs `git add -N` on untracked new files (intent-to-add), dispatches the requested review callees (rules-review / skill-review / publicity-review / verify-diff / tidy) in order, then `git reset -- <paths>` to restore the untracked state. Holds a closed list of each callee's visualization and restore-safety assumptions. Non-interactive — no user prompts. Project-local routine — not for marketplace distribution.
allowed-tools: Read, Bash(git status --porcelain*), Bash(git add -N *), Bash(git reset -- *), Bash(git rev-parse *), Skill(rules-review), Skill(skill-review), Skill(publicity-review), Skill(verify-diff), Skill(tidy)
---
# Review With Untracked
Review callees that derive their review scope from the git working-tree diff are **blind to untracked new files** — `git diff <base>` excludes paths that are not yet tracked, so a brand-new file created during a task is invisible to them. This skill brackets a review chain so those callees can see untracked new files: it runs `git add -N` (intent-to-add) on the untracked new files so they appear in `git diff <base>` as `+` additions, dispatches the requested review callees in order, then runs a path-scoped `git reset -- <paths>` to return the files to untracked.
The skill is **project-local** (lives under `.claude/skills/review-with-untracked/`, not registered in `.claude-plugin/marketplace.json`) and non-interactive — designed to be wrapped by review-orchestrating routines (e.g. `dev-workflow`'s `hooks.on_complete`, `dev-workflow-triage`, `triage-review`).
## No-Stall Principle
This skill is non-interactive and has **zero user-judgment gates**. Every callee return is a structured return value to parse-and-proceed-past, never a checkpoint to confirm with the user. The only user-facing output is the § Return contract verdict at the end.
**Permissible fatal-abort exits** (emit the § Return contract in `status: "error"` form and stop) — closed list:
- Not inside a git work tree, or `Base ref` does not resolve to a commit (`git rev-parse <Base ref>` fails) → `reason: "base ref unresolved"`.
- `Callees` is empty, or contains a name outside the § Closed list dispatch vocabulary → `reason: "unknown callee"`.
Everything else is non-fatal — record and continue:
- A callee dispatch error or unparseable verdict — record it under that callee's per-callee status and proceed to the next callee.
- A `corrupted_paths` detection (§ Procedure step (f)) — recorded and surfaced in the verdict, never an abort.
**Callee return-point reminder**: after a callee's verdict is parsed, the next tool call — the next callee dispatch, or step (e) restore when the last callee returned — must be issued in the same turn. Do not insert a "shall I proceed?" turn or re-render a callee verdict as a standalone deliverable.
**Restore is mandatory on every normal and callee-error exit path** (§ Procedure step (e)). A hard tool-level error or session death between step (c) and step (e) is out of scope for this principle — § Constraints names the resulting leftover-`A` window.
## Invocation contract
The caller passes these fields in natural language (the skill extracts them from the invocation text):
- `Base ref` *(optional, default `HEAD`)* — the git ref the review callees diff against. Forwarded to each callee in the callee's own argument form (see § Closed list).
- `Callees` *(required)* — an ordered list of callee names to dispatch, each drawn from the § Closed list dispatch vocabulary. Dispatched in the given order.
- `Scope` *(optional)* — additional path globs to exclude from visualization, on top of the always-excluded workflow-artifact paths (`.claude/plans/**`).
## Closed list of per-callee visualization & restore-safety assumptions
The list scope is **review callees that derive their review scope from the git working-tree diff** (`git diff <base>`, or `git status --untracked-files=all` for untracked in `tidy`'s default mode) — the only callees `git add -N` visualization affects. It records, per callee: how it scopes its diff, whether it is blind to untracked files without visualization, its **restore-safety class** (whether its internal `git checkout HEAD -- <file>` rail handles a HEAD-absent file), and the argument form this skill passes it.
`git add -N` is the bridge: `git diff <ref>` excludes untracked files but **includes** intent-to-add files, so visualizing an untracked file turns it into a reviewable `+` hunk.
| Callee | Diff-scope mechanism | Untracked visibility (without add -N) | Restore-safety class | Argument form |
|---|---|---|---|---|
| `rules-review` | `git diff --name-only <base>` | blind | safe — detect-only (no `Edit`, no rail) | `--base-commit <sha>` |
| `skill-review` | `git diff <Base ref>` | blind | **unsafe** — frontmatter rail `git checkout HEAD -- <file>` has no HEAD-absent handling | `Base ref: <ref>` |
| `publicity-review` | `git diff <Base ref>` | blind | **unsafe** — same frontmatter rail | `Base ref: <ref>` |
| `verify-diff` | `git diff <Base ref>` | blind | **unsafe** — same frontmatter rail | `Base ref: <ref>` |
| `tidy` | `git status --untracked-files=all` (default mode) | native — collects untracked itself | safe — HEAD-absent specialization in its rail | default mode (no `Base ref`) |
The restore-safety column reflects each callee's `git checkout HEAD -- <file>` safety rail — anchored in `skill-review` / `publicity-review` / `verify-diff` § "Per-iteration safety rails" (c) (the three `Base ref:` editors share one **unsafe** rail with no HEAD-absent handling), in `tidy`'s HEAD-absent specialization in its own rail, and in `rules-review`'s absence of a rail (detect-only). Re-check this column if a callee changes its safety rail.
The five rows above are also the **dispatch vocabulary**: a `Callees` name outside this set is an unknown-callee fatal abort (§ No-Stall Principle).
**Out-of-scope (not diff-deriving, so visualization is irrelevant — never valid `Callees` entries)**:
- `prompt-tuning` — evaluates a path-targeted prompt file; does not run `git diff`.
- `ask-peer` — reviews a caller-supplied payload; does not run `git diff`.
- `verify-bundle-sync` — a structural directory comparison (`diff -rq` of the canonical vs bundle-copy trees) that ignores the base ref; diff-independent, so visualization has no effect on it.
Runtime uses of the list: (a) validate each requested callee name; (b) pick the per-callee argument form; (c) decide whether visualization is needed — apply it once when any requested callee is `blind`; (d) read the restore-safety class — when any requested callee is **unsafe**, enable the step (f) detect-and-warn pass.
**Argument-form minimalism**: pass each callee only the single argument form above — no triage branch name, no changed-file list, no extra context. A long preamble can override the callee's own procedural logic and cause an empty-input early return; for `skill-review` the `Base ref: <ref>` line is the entire argument.
**`tidy` scope caveat**: `tidy`'s default mode diffs working-tree-vs-HEAD, so its review scope is `Base ref`-independent and equals the other callees' `<Base ref>` scope only when `Base ref == HEAD` — against a multi-commit base its findings cover only the uncommitted delta while the `Base ref:` callees cover the full base-to-tree range. This divergence is accepted because default mode is how `tidy` natively sees untracked files (the whole reason it is `safe` rather than needing visualization).
## Procedure
Single invocation, top to bottom:
(a) **Validate inputs, then resolve the base.** First validate `Callees` (no git command needed): confirm it is non-empty and every name is in the § Closed list dispatch vocabulary; on a miss, take the unknown-callee fatal abort (§ No-Stall Principle) with `base: null`. Only after the names pass, run `git rev-parse <Base ref>` to a concrete `<sha>`; on failure, take the base-ref-unresolved fatal abort (§ No-Stall Principle) with `base: null`. Both checks run before any git mutation — step (c) is the first mutation, so a fatal abort in this step never leaves an intent-to-add entry behind.
(b) **Collect untracked new files.** Run `git status --porcelain=v1 --untracked-files=all -z` and take the `??` entries. Subtract the always-excluded `.claude/plans/**` workflow-artifact paths and any `Scope` excludes; hold the remainder as `visualized_paths` — the *candidate* set to visualize. (The verdict's `visualized_paths` field reports only what step (c) actually runs `git add -N` on, so it is the empty set whenever visualization is skipped — including when no requested callee is `blind`.) Gitignored files never appear in this output, so they are excluded automatically (intended). If `visualized_paths` is empty, skip visualization — step (c) and the step (e) restore become no-ops — but the callees still run in step (d).
(c) **Visualize** — only when at least one requested callee is `blind` (per § Closed list) and `visualized_paths` is non-empty. Run `git add -N -- <visualized_paths>`. An empty file is visualized as `new file mode` with no `+` hunk; a callee sees the path with no content delta and treats it as a no-op, which is acceptable. `visualized_paths` is sourced exclusively from step (b)'s `??` entries, so `git add -N` never touches a tracked path.
(d) **Dispatch callees in order.** For each name in `Callees`, in order: emit a one-line Progress Visibility status, then dispatch `Skill(<callee>)` with its § Closed list argument form (substituting the step (a) `<sha>` for `rules-review`, the `<Base ref>` for the `Base ref:` callees). However the host services the call — inline in this same context, or as a separate agent — the callee emits a single fenced JSON verdict block; parse that block (ignore any prose preceding it) and record its `status`. An inline-serviced verdict is a normal result, not a failure. Only a tool-level dispatch error or a missing / unparseable verdict is the non-fatal failure path — record it under that callee's per-callee status (`dispatch-error` / `unparsed`) and proceed to the next callee. **Return-point reminder**: issue the next callee dispatch — or step (e) when this was the last callee — in the same turn (§ No-Stall Principle).
(e) **Restore (mandatory on every normal and callee-error exit path).** When visualization was applied in step (c), run `git reset -- <visualized_paths>` to drop the intent-to-add entries and return the files to untracked. **Use the path-scoped form only — never bare `git reset`**, which would also unstage any unrelated content the caller had staged before invocation. **`git reset -- <paths>` is unstage-only: it preserves working-tree content (including any corruption a callee left behind) so step (f) can inspect it. Reordering this step after (f), or replacing it with `git checkout` / `git restore`, would break detection — do not.**
(f) **Detect-and-warn** — only when a requested callee is **unsafe** (per § Closed list) and visualization was applied. The unsafe callees' frontmatter rail (`git checkout HEAD -- <file>`) cannot revert a HEAD-absent (visualized) file, so a frontmatter-corrupting edit can survive. `Read` each `visualized_paths` entry and collect into `corrupted_paths` any path that is now corrupted:
- **Primary detector (signal #2)**: re-parse the file's YAML frontmatter yourself (orchestrator-side, independent of callee behavior). A path whose `---`-delimited frontmatter no longer parses is corrupted. A file without a frontmatter block is never flagged.
- **Corroborating (signal #1)**: a callee verdict that reported a rail conflict (`status: "conflict"`, `reason: "frontmatter broken"`) referencing the path.
Signal #2 is **primary** because the unsafe callees emit `frontmatter broken` without checking their `git checkout` exit code — signal #1 works today but would silently go dark if a callee revision gated its verdict on checkout success. This pass **warns only**: it does not restore content, since auto-restore would also discard any legitimate in-scope fix a callee applied (see § Constraints).
(g) **Emit the § Return contract verdict** and stop.
## Constraints / boundary
- **Callees must not stash or reset during visualization.** This skill's callees run while `visualized_paths` are in intent-to-add state; a callee that ran `git stash` / `git reset` itself would disturb that state. The current callee set does not (only `triage-review` stashes, and it is a *caller* that wraps this skill, never a callee of it).
- **Non-breaking callee edits persist (intended).** When a callee edits a visualized file's frontmatter *without* breaking it — or edits its body — no rail fires and the edit survives on the file after step (e) returns it to untracked. This is intended: the skill exists to let callees review and fix new files. `corrupted_paths` surfaces only frontmatter *breakage*, not legitimate edits.
- **Hard-crash leftover window.** Step (e)'s restore is a procedural instruction, not a `try`/`finally` primitive: a hard tool-level error or session death between step (c) and step (e) can leave a `visualized_paths` entry in intent-to-add (` A`) state with a clean-looking working tree. The skill does **not** auto-reset orphan ` A` entries on a later run (that could clobber a caller's own intentional intent-to-add). Recover manually with `git reset -- <path>` if it occurs.
- **Permission-matcher fallback.** If a host's permission matcher rejects the scoped `Bash(git reset -- *)` / `Bash(git add -N *)` grants, broaden them to `Bash(git reset *)` / `Bash(git add *)` but keep the scoped invocation forms (`git reset -- <paths>` / `git add -N -- <paths>`) — the path scoping is the safety property; the grant pattern is only how the host authorizes it.
## Return contract
End the response with a single fenced JSON block:
```json
{
"status": "ok|error",
"base": "<sha>",
"visualized_paths": ["<path>"],
"corrupted_paths": ["<path>"],
"callees": [
{"name": "<callee>", "status": "<callee verdict status, or 'dispatch-error' / 'unparsed'>"}
],
"reason": null
}
```
Field semantics:
- `status`: `error` only on a § No-Stall Principle fatal abort (with `reason` set); otherwise `ok`, including runs where individual callees errored (those surface in `callees[].status`) or `corrupted_paths` is non-empty.
- `base`: the concrete `<sha>` resolved in step (a), or JSON `null` when a fatal abort fired before base resolution (unknown callee, or base ref unresolved).
- `visualized_paths`: the exact set `git add -N` ran on (empty when visualization was skipped).
- `corrupted_paths`: a subset of `visualized_paths` flagged by step (f) (empty when step (f) did not run or found nothing).
- `callees`: one entry per dispatched callee, in dispatch order, carrying the callee's own verdict `status` verbatim (or `dispatch-error` / `unparsed` for a non-fatal dispatch / parse failure). Each callee defines its own status vocabulary (they are **not** a single unified enum across callees), so this is a pass-through value — a consumer must read it per-callee, not switch on it as one enum.
- `reason`: a short string on `status: "error"`, else JSON `null`.
## Sub-skill caller directive
When invoked via `Skill(review-with-untracked)` from an orchestrator, the fenced JSON verdict is the **structured return value** of this skill's procedure — not a deliverable to the user, and emitting it does **not** terminate the orchestrator's turn. The same agent must immediately issue the next tool call the orchestrator's flow dictates. Do not insert a prose summary or a "shall I proceed?" sentence between the JSON verdict and the next tool call. Closing the turn after emitting the JSON block — even with no prose between them — is the same violation as inserting prose. Only one fenced JSON block — the verdict — appears in the response, so callers can locate it unambiguously.
## Related
- `triage-review` — operator routine that dispatches the same review callees against a committed `main..HEAD` stack; the structural model for this skill's orchestrator shape. It auto-stashes, so it is a *caller* that could wrap this skill, never a callee.
- `verify-diff` / `skill-review` / `publicity-review` / `rules-review` / `tidy` — the review callees this skill brackets; their untracked-visibility and restore-safety classes are tabulated in § Closed list.