Prime the session with architectural rules for the current task — universal + language + domain + project tiers — the deep pass on top of the rule-prime hook's floor. Auto-fires on the first substantive task, after /clear, and on topic shift; asks before re-priming on drift. Manual trigger /prep. Not for trivial questions.
Installs into .claude/skills of the current project.
Are you the author of Prep?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/ackeskin-prep)
---
name: prep
description: "Prime the session with architectural rules for the current task — universal + language + domain + project tiers — the deep pass on top of the rule-prime hook's floor. Auto-fires on the first substantive task, after /clear, and on topic shift; asks before re-priming on drift. Manual trigger /prep. Not for trivial questions."
---
# prep
The prep organ. Consumes [discover](../discover/SKILL.md), [deliver](../deliver/SKILL.md), the [architectural-rules tree](../../architectural-rules/README.md), and project `.claude/architecture.md` (when present, per [project-architecture.md](../../docs/project-architecture.md)).
Prep **prevents** drift by priming Claude with the rules *before* code is written. Review **detects** drift after the fact. Different jobs, complementary.
## When to run
**Auto-fire** (the description field above drives this — Claude reads it and fires the skill at the right moment):
1. **First substantive task of a session.** A substantive task is a code-writing, design, debugging, or review request. Trivial questions, lookups, and "what is X" style prompts do *not* trigger prep.
2. **First substantive task after `/clear`.** Context was wiped; re-prime.
3. **User signals a topic shift.** Phrases like "now let's work on X", "switching to Y", "different question about Z" where Z is a new domain / language / project.
**Manual fire:**
4. User types `/prep` (explicit trigger, e.g. when Claude failed to auto-fire, or the user knows they are about to shift).
5. User asks "prep for this" / "load architectural rules" / "prime for X".
**Do not auto-fire on:**
- Session start itself (nothing to prep against yet).
- Trivial questions / pure information requests ("what does git reflog do?").
- Every message — prep is *per-task*, not per-turn.
## Inputs
- **Task text.** The substantive request that triggered prep. If invoked manually via `/prep [scope-hint]`, use the hint to bias scope detection.
- **Working directory.** `$CLAUDE_PROJECT_DIR` if set, otherwise `cwd`. Determines project context and whether a `.claude/architecture.md` is available.
- **Recent session state.** Earlier turns in the same session (for topic-shift detection).
## Procedure
### 0. Read the floor watermark (rule-prime hook handoff)
The **rule-prime hook** primes the *floor* — always-tier + project-tier rules, plus the one language tier in a single-language repo — mechanically at `SessionStart`, and incremental tiers per prompt at `UserPromptSubmit`. It records what it primed in a per-session watermark (`~/.claude/session-state.json`, key `rulePrime`, keyed by session id): `{ scopes: [...], floorPrimed: true|false, droppedRules: [...], language, polyglot }`. When the floor exceeds its token budget the hook drops rules, sets `floorPrimed: false`, and lists the dropped rule keys in `droppedRules` — the watermark records what actually reached context, and the dropped rules are prep's to backfill.
Before priming, read that watermark:
- **Watermark present + `floorPrimed: true` (and `droppedRules` empty or absent)** → the full floor is already in context. Prep runs the **deep pass**, not a re-prime: announce *"floor primed by the hook (scopes: …) — running deep pass"*, then proceed to step 1 with the floor's scopes treated as already-loaded. In step 4, **do not re-emit** rules whose scope is entirely within the watermark's `scopes` (they are already in context); surface only what the deep pass *adds* — higher top-N, the task-specific domain tier, `.claude/architecture.md`, and any language tier the polyglot floor deferred.
- **Watermark present + `floorPrimed: false` (or `droppedRules` non-empty)** → the floor is **partial**: the rules named in `droppedRules` were resolved but never injected. Announce *"partial floor (dropped: …) — backfilling in deep pass"*, then run the deep pass as above **and re-emit every rule named in `droppedRules`** with its full body in step 4 — even when its scope appears in the watermark's `scopes`. Deferring a dropped rule leaves a silent gap; backfill takes priority over the step-4 dedupe.
- **No watermark (hook disabled, or non-hook environment)** → prep owns the floor as before. Run the full procedure from step 1 with nothing pre-primed. This is the unchanged legacy path — prep degrades gracefully when the hook is off.
The watermark is advisory and read-only here. Prep never writes it; it is the hook's artefact. If the watermark is malformed or unreadable, treat it as absent (full prime) — fail toward priming, never toward a silent gap.
### 1. Identify task scope
**First — resolve the active region (scope-resolution).** Before inferring scope from the task text, run the [scope-resolution resolver](../../docs/scope-resolution-resolver.md) for the task path: the downward longest-prefix walk over `<repo>/.claude/submodules.md` + `<path>/.claude/submodule.md` + `<dir>/.claude/scope.md`. It returns the effective `(corpus-source, scopes, kind, inherit-parent, active-submodule)`. Seed the detection below with this result — the resolved scopes are a prior on Language/Domain, and `corpus-source` selects which corpus the §2 discover call targets (`submodule` → the submodule's own corpus; `parent` → the enclosing corpus + the submodule's scopes; `none` → no rules, an out-of-discipline subtree). **No `submodules.md` (or no match) → single-tree, this step is a no-op and detection proceeds exactly as today** (the no-regression invariant). The walk is prose the resolver doc owns — do not re-derive the manifest formats.
Then, from the task text + project context (seeded by the resolved region), determine:
- **Task type** — one of: `code-writing`, `design`, `debugging`, `review`. Drives `relevance_phases` filter to discover.
- Code-writing: explicit "implement", "add", "write", "refactor", "fix".
- Design: "design", "plan", "how should we structure", architectural questions.
- Debugging: "debug", "not working", "fails with", error traces.
- Review: "review", "look over", "check this code".
- Default when ambiguous: `code-writing`.
- **Language(s).** From file extensions mentioned in the task, cwd-visible repo indicators (`package.json`, `*.csproj`, `CMakeLists.txt`, `.unity` packages), codemap, or explicit mention. Multiple allowed.
- **Domain(s).** From module names (`api`, `ui`, `rendering`, `auth`), task keywords, file paths. Multiple allowed.
- **Project.** The current working directory's project. If `<project-root>/.claude/architecture.md` exists, flag it for explicit read in step 3.
When scope detection is thin (no clear language / domain / obvious keywords), fall back to `[global, universal]` only and note the thin detection in the priming block.
### 2. Build the discover query
Invoke [`skills/discover/SKILL.md`](../discover/SKILL.md) programmatically:
```
{
task_keywords: [<derived from task text>],
scopes: ["universal", <detected language>, <detected domain>, "global", "project-<name>"],
kind: "architectural-rule",
relevance_phases: [<task-type mapping>, "always"],
top_n: 20,
render_bodies: true,
include_recaps: false
}
```
`relevance_phases` mapping:
| task type | phases |
| --- | --- |
| `code-writing` | `always`, `when-language-<lang>`, `when-domain-<domain>`, `when-touching-<X>` (every touching-target the task's files satisfy) |
| `design` | `always`, `during-planning` |
| `debugging` | `always`, `during-debug` |
| `review` | `always`, `during-review` |
`include_recaps: false` is deliberate — prep primes *what rules apply*, not *what I was doing last time*. Recaps are for the discover report, not the priming block.
Discover resolves the architectural-rule tier overlay as part of this call — the rules prep receives are already the *effective* corpus (user / company / project overrides + patches applied, disables dropped, anchors stripped). Prep does not re-resolve; it consumes the resolved set and carries any non-default annotations through to step 5.
### 3. Read `.claude/architecture.md` if present
If the project has `<project-root>/.claude/architecture.md`, Read it and treat its content as an additional fragment. Compose it with the discover output in step 4. Do not rely on discover to surface it — discover's codemap branch covers `codemap.md`, not `architecture.md`.
### 4. Merge, prioritise, cap
Combine discover's rendered fragments + the architecture file content.
**Sort** by specificity (highest → lowest):
1. Project-specific — `scope` includes `project-<name>` tag, or content is from `.claude/architecture.md`.
2. Domain — matched by `scope` containing a domain tag from step 1.
3. Language — matched by `scope` containing a language tag from step 1.
4. Universal — `scope` contains `universal` or `global`.
**Cap:**
- Hard cap at 20 rules. When more match, drop from the lowest-specificity tier first (universal → language → domain, never drop project-specific rules within the cap).
- Soft cap: the priming *summary block* targets < 500 tokens (rule names + one-line gists). Rendered rule bodies delivered on top of it are budgeted separately by deliver's per-body caps — the 500 figure never counts bodies. If the 20-rule set exceeds this, drop lower-specificity rules until the block fits. Do not paraphrase — delivery's source-of-truth rule forbids it.
**Compression:**
- The architectural-rules tree already enforces rule-level compression at storage time. Do not re-compress here.
- If the `.claude/architecture.md` content is long (>10 bullets), pull the most-relevant sections to the task; leave the rest for an explicit user request.
### 5. Surface the priming block
Output shape:
```
Prepped for: <language(s)> / <domain(s)> / project: <name>
Loaded N rules:
Universal: <terse rule list, comma-separated or bulleted>
Language: <terse rule list>
Domain: <terse rule list>
Project: <terse rule list>
Codemap age: X days. Architecture file: present | absent.
```
Rules lines use the rule's `name` field from frontmatter (short, memorable). When a rule's name alone is not self-explanatory, add its one-line description inline — keep each line terse.
**Overlay annotations — non-default only.** A rule overridden / patched / disabled / locked-diverged carries a short tag inline (`[user override]`, `[user patch −1~1+1]`, `[⚠ orphaned anchor]`, `[⚠ LOCKED divergence]`). Plain shipped rules carry no tag — the common case stays clean. This is the only addition to the priming block; it costs tokens only when something actually diverges from shipped.
**Empty-result shape** (no rules matched):
```
Prepped for: <detected scope>
No architectural rules matched.
Either this scope has no captured rules yet, or the task scope was misidentified.
Proceeding without priming. Run /prep manually if you want to provide context.
```
Show the priming block to the user before starting work. They see what was loaded and can correct if irrelevant ("you prepped for cpp but this is a TypeScript file — re-run with `/prep typescript`").
### 6. Record primed scope
Maintain a short in-context note — not a file, ephemeral per session:
```
Primed for: language=<lang>, domain=<domain>, project=<name>. N rules loaded.
```
Update this note every time prep re-runs. It is the comparand for the task-shift rule below.
### 7. Task-shift rule (continuous, not a one-time step)
Throughout subsequent work, observe:
- **Does the current request mention a different module / domain / language than the primed scope?**
- **Is Claude about to read or write files outside the paths implied by the primed scope?**
- **Has the user's intent clearly shifted topic** (even before files are touched)?
When any of those is true, stop and say:
> This looks like it may be moving outside the original scope (primed for **X**; now touching **Y**). Re-prep?
- User answers. On yes → re-run from step 1 with the new scope. On no → proceed with existing priming. Update the primed-scope note either way.
- **Budget:** at most one such prompt per 3 file operations in a row. Prevents thrashing when Claude is touching many files across modules.
- **False-positive cost is low** (user just says "keep going"), **false-negative cost is low** (user can `/prep` manually). Asymmetry favours asking — err on the side of surfacing.
No state tracking of file sets. No silent detection. Observe → surface → ask. Matches the collaborator principle.
**Boundary-cross specialization (scope-resolution).** When the repo has a `submodules.md`, the task-shift watch above gains a sharper trigger: the active region the [resolver](../../docs/scope-resolution-resolver.md) computes for the new task path. The cross-type — and the response — keys off the **filename**, never the contents:
- **Submodule cross** — the task path enters a *different* `submodule.md`-bearing registered path → treat as a re-prep event (the prompt above), noting the region change (`Submodule: services/api (go) → apps/web (ts)`); the new region may carry a new language/corpus.
- **Subfolder cross** — the task path crosses a `scope.md` boundary *within the same submodule* → **silent filter swap**: merge the new scopes, no prompt (it's a refinement, not a region change).
- **Vendored entry** — the task path enters a `kind: vendored` region → surface *"Entered vendored region — discipline disabled. Limit edits to upstream-compatible changes."* and do not propose refactors to that subtree.
This is the same observe→surface→ask mechanism, scoped to declared boundaries. **No `submodules.md` → none of this fires** (no-regression).
### 8. Push-back handling (continuous, not a one-time step)
When the user corrects Claude with reference to a rule ("you violated SoC", "this imports /api directly — go via services", "that's not how we do naming here"):
1. Note the correction.
2. Identify whether the correction maps to:
- **A rule already in the primed set.** Claude missed it — acknowledge, adjust the code, no capture needed (the rule exists).
- **A rule not in the primed set but already captured.** Prep's scope detection missed it — acknowledge, offer to re-run `/prep` with broader scope.
- **A rule that does not exist in the tree.** Propose a capture: *"This correction looks like a new rule. Capture it via `/capture`?"* — invokes [`skills/capture/SKILL.md`](../capture/SKILL.md) with the user's correction text as candidate content. Capture's own confirmation flow runs.
3. Never auto-capture. Collaborator principle.
## Failure modes
- **Scope detection returned `[global]` only.** The task was vague. Surface the thin detection explicitly in the priming block so the user can override. Do not guess a more specific scope.
- **Discover returned zero fragments.** Use the empty-result shape from step 5. Do not fabricate rules.
- **`.claude/architecture.md` is huge (>500 lines).** Read only the sections relevant to the task scope. If relevance is unclear, summarise: *"Project has a large architecture.md — loaded sections matching <scope>; the rest is available on request."*
- **Task-shift prompt fires too often.** Budget kicks in at 1-per-3 file operations. If budget is exhausted and drift still seems real, wait until the next file operation window rather than skipping acknowledgement entirely.
- **Push-back maps to no existing rule AND no clear captureable text.** Ask one clarifying question (*"Should this be a project-specific rule, a language rule, or a universal rule?"*) before proposing capture.
## What prep does NOT do
- **Does not monitor keystrokes or tool calls in real time.** Task-shift is observed at Claude's own judgement boundaries (about to read / write), not continuously.
- **Does not persist primed scope across sessions.** Ephemeral per session.
- **Does not review code for rule violations.** That's review. Prep primes; review audits.
- **Does not auto-capture new rules.** Push-back produces a capture *proposal*, never a silent write.
- **Does not substitute for the user's architectural judgement.** Surfaces rules, the user decides which apply in context.
- **Does not modify rule files.** Read-only over the architectural-rules tree.
- **Does not include session recaps.** `include_recaps: false` on the discover call. Recaps are episodic recall, orthogonal to rule-priming.
## Relationship to other organs
- **discover** — prep's retrieval engine. Prep never re-implements discovery logic.
- **deliver** — prep passes `render_bodies: true`; deliver handles tier ordering and caps within its own contract.
- **capture** — push-back → capture proposal. Prep never writes directly.
- **architectural-rules tree** — the corpus prep primes from. Prep's quality is bounded by the corpus's quality.
- **project-architecture.md** — the project's canonical architectural file. Prep reads it directly (step 3), not via discover.
- **review** — review consumes the same primed scope signal. For now, prep's primed-scope note is session-internal only.
- **recap** — prep does not load recaps into the priming block. Recaps belong in `/discover`-style recall, not rule priming.
- **rule-prime hook** — the mechanical half of priming. The hook owns the *floor* and records it in the `rulePrime` session watermark; prep reads that watermark (step 0) and runs the *deep* pass instead of re-priming. When the hook is off, prep owns the floor (the legacy path). Rationale + the drift flag: [`docs/prep-organ.md`](../../docs/prep-organ.md).
- **persist-before-discard rule + clear-context-decision-guard hook** — prep surfaces the rule like any other when the scope matches session-close; the hook is the mechanical backstop. Rule and hook must stay aligned. Rationale: [`docs/prep-organ.md`](../../docs/prep-organ.md).
See [`docs/prep-organ.md`](../../docs/prep-organ.md) for the scope map and the rationale behind each rule.