- name
- project-init
- description
- Get a repository ready for the dev-team toolchain in one command — detect the tech stack (JS/TS, Python, C#, Java), inventory the static-analysis tools the project already has, confirm a plan, and install only what's missing, repo-level. This is the canonical source of truth for tech-stack detection and toolchain installation — NOT dev-team-specific config (CLAUDE.md generation, agent template activation, PostToolUse hooks, the generated `/pr` command all live in `/setup`, which invokes this skill first for the stack signal). Also installs the detection-gated capability tools other skills depend on — semgrep, Playwright + Chromium, adr, gh, and the docker scanners (hadolint/trivy/grype). For JavaScript it scaffolds a new project with ES modules, functional style, prettier, oxlint, editorconfig, vitest, and gitignore. Use this skill whenever the user wants to start a new JS project, scaffold a Node.js app, create a new package, bootstrap a JavaScript repo, or says things like "init a new project", "set up a JS project", "create a new node app", "start a new frontend project", or "bootstrap a new package". Also trigger when the user says "set up my project's toolchain", "install the linters for this repo", "get this repo ready for the plugin", or asks to add standard tooling (linting, formatting, testing) to a new or existing project in any supported language.
- role
- worker
- user-invocable
- true
- argument-hint
- [--yes] [--force]
# Project Initializer
One command to get a repository ready for the dev-team toolchain, whatever
the stack. Detect the project's language(s), inventory the static-analysis
tools already present, confirm a three-column plan, then install only the
missing tools — lane tools and Playwright always repo-level, never
user-level or global. It then installs the detection-gated **capability
tools** other skills depend on (semgrep, Playwright, adr, gh, docker
scanners — see Step 4b), which are user/system-level CLIs by nature.
Supported stacks: **JS/TS**, **Python**, **C#**, **Java** — the four lanes
registered in
`${CLAUDE_PLUGIN_ROOT}/skills/static-analysis-integration/references/tool-configs.md`
§ Build-time lanes. Tool facts (choice, versions, install mechanism) follow
that registry; provider-binding semantics (capability slots, ordered
provider lists, bind-don't-replace, the qualification contract) follow
`${CLAUDE_PLUGIN_ROOT}/skills/build/references/static-self-heal.md`. The
manual commands stay documented in
`${CLAUDE_PLUGIN_ROOT}/skills/static-analysis-integration/references/language-setup.md`;
this skill automates them.
## Arguments
Arguments: $ARGUMENTS
- `--yes`: Run unattended — auto-confirm each gate below with its **safe**
default and never wait for input. `/setup --yes` passes this through.
- `--force`: Bypass Step 0's idempotency short-circuit and force the full
Step 1-6 sequence even when `.claude/init-state.json` records a matching
`last_run` (#1778). Independent of `--yes` — combine them to force a full
unattended re-check.
### `--yes` semantics
**Affirmative** (auto-confirm, no prompt):
- **Step 3 three-column plan** — proceed: install the "missing and will add"
column's defaults, repo-level. Existing configs are still never overwritten
(that is already the plan's contract, not a prompt).
- **Step 4b capability tools** — install every tool whose detection signal
fired and that is still missing. Tools whose signal did not fire are still
not installed.
- **Step 4c CodeGraph** — install if missing (its recommended default is
already yes, as part of the interactive keyless-pair prompt — see Step 4c).
CodeGraph never writes to the repo, so it stays in this bucket. Repowise,
offered alongside it in the same interactive prompt, does **not** stay
here — see the Conservative bucket below (#1690).
**Conservative** (skip with a printed note — never mutate the repo by
surprise):
- **Step 4c Graphify** — skipped for this run, because `graphify install
--project` writes PreToolUse hook entries embedding this machine's
absolute binary path into the shared, git-tracked `.claude/settings.json`
(see the settings.json absolute-path guard, #1367, in the Graphify
sub-section below) — a write that file cannot simply be gitignored out of
(unlike the generated git hooks themselves, which are). It also writes a
`## graphify` section into the tracked `.claude/CLAUDE.md`. Print
`Graphify: skipped under --yes (repo-writing; run /project-init without --yes to add it)`
and do **not** record a durable decline in `.claude/init-state.json`, so a
later interactive run still offers it.
- **Step 4c Repowise** — skipped for this run, because `repowise init` writes
a `## Codebase Intelligence for <project> (Repowise)` section into the
tracked `.claude/CLAUDE.md` (see the Repowise sub-section below) — the same
class of repo-level write Graphify is gated for above (#1670 item 3 made
this write explicit; #1690 is what moves Repowise to this bucket to match).
Repowise's own `.mcp.json` write also carries a machine-specific path, but
that file IS gitignored by the standing check below — it is the tracked
CLAUDE.md write, not the `.mcp.json` write, that puts Repowise here. Print
`Repowise: skipped under --yes (repo-writing; run /project-init without --yes to add it)`
and do **not** record a durable decline in `.claude/init-state.json`, so a
later interactive run still offers it as part of the keyless-pair prompt.
CodeGraph, the other half of that same prompt, is unaffected — it stays in
the Affirmative bucket above and installs under `--yes` regardless.
- **Step 1 zero/ambiguous stack** — never guess. Report the supported stacks
and exit gracefully without writing files or installing anything, exactly as
the interactive path's "something else" branch.
- **Greenfield JS/TS scaffold** — the confirm step proceeds with the documented
defaults (no customization prompt); it only writes into an empty/near-empty
directory, so nothing existing is overwritten.
## Workflow
### Step 0: Idempotency short-circuit (#1778)
`/project-init` is invoked far more often than it has anything new to do —
most re-invocations find every slot still bound and every capability tool
still resolved (installed or durably declined), and re-running the full
Steps 1-6 sequence for that outcome burns tokens presenting a three-column
plan whose answer never changed. This step does not skip detection — it
only skips Step 3's plan presentation and any install when detection itself
proves there is nothing to install.
1. **Always run Step 1's stack detection, Step 2's tool inventory, Step
4b's capability-tool detection signals, and Step 4c's "Detect which are
already present" probes first** — all cheap, deterministic,
filesystem/PATH-only signals with no network and no builds, so running
them here is not new work, only reordered. Their live result is
authoritative for step 2 below — never substitute a cached value for
what they just found, per this file's own stale-state override rule
(§ "Detect which are already present").
2. **Short-circuit** only when `--force` was **not** passed AND the just-run
detection shows: the stack list matches `.claude/init-state.json`'s
`last_run.stack` (if the key is absent, this condition fails and step 3
below never fires — first run always takes the full path), Step 2's
fresh inventory has every lane's capability slot bound (Step 3's own
"missing and will add" column would be empty), and every Step 4b/4c
capability tool is installed or durably declined per its own
already-present/decline state (never "signal fired, decision still
open"). All three are re-derived from the live probes just run, not read
back from `last_run` — `last_run.stack` is the only field compared
against a recorded value, because the other two must reflect what the
filesystem shows *right now*, exactly as an uninstalled tool or a wiped
config file must be caught on this very run, not papered over by a
stale cache.
3. **Before stopping, still run both of this file's standing checks** —
the `.mcp.json` machine-specific-path hygiene scan (§ "Standing check —
`.mcp.json` machine-specific-path hygiene") and Graphify's settings.json
absolute-path scan (§ "Standing check — run even when Graphify install
is skipped") — both are explicitly documented elsewhere in this file as
running "unconditionally, once per `/project-init` (and therefore
`/setup`) run," independent of every other branch, and a short-circuited
pass is not an exception to that. Fold their one-line outcomes into the
short-circuit's own report.
4. Print exactly one line reporting both the short-circuit and the standing
checks' outcomes — e.g. `Project already initialized for <stack> —
nothing changed since the last run (.claude/init-state.json); .mcp.json
hygiene: <outcome>; Graphify path check: <outcome or "not applicable">.
Re-run with --force to re-check anyway.` — and stop. Do not proceed to
Step 3's plan presentation or any install step.
5. **Otherwise** (first run, no `last_run` key, a changed stack, an unbound
slot, an unresolved capability tool, or `--force`), proceed to Step 3 as
normal with the detection/inventory results already in hand from step 1
above — do not re-run them a second time.
6. **`--force`** always bypasses this short-circuit and forces the full
Step 1-6 sequence, exactly as if `last_run` were absent (already listed
in the Arguments section above).
On a normal, successful completion, Step 6 writes the `last_run` snapshot
into `.claude/init-state.json` — see its final bullet below. A run that
stops early (Step 1's zero/ambiguous-stack exit, an install failure) does
not write `last_run`, so the next invocation naturally re-checks from
scratch rather than caching a failed or incomplete state as "done."
### Step 1: Detect the stack
Probe the working directory with cheap, deterministic filesystem signals —
no builds, no network:
| Signal | Stack |
|---|---|
| `package.json`, `tsconfig.json`, `*.js`/`*.jsx`/`*.ts`/`*.tsx` sources | JS/TS |
| `pyproject.toml`, `requirements*.txt`, `setup.cfg`/`setup.py`, `*.py` sources | Python |
| `*.sln`, `*.csproj`, `global.json` | C# |
| `pom.xml`, `build.gradle`/`build.gradle.kts`, `*.java` sources | Java |
- **Multiple stacks detected** → multi-stack setup: run every matched
language's inventory and install, mirroring the self-heal pass's
mixed-language lane dispatch.
- **Zero or ambiguous signals** (empty dir, README-only repo) → **ask the
user**: present the four supported stacks plus "something else".
"Something else" explains what's supported and exits gracefully — no
files written, nothing installed. **Under `--yes`, do not prompt** — never
guess a stack: report the supported stacks and exit gracefully, exactly as
the "something else" branch.
### Step 2: Inventory the existing toolchain
Stack detection says which lanes apply; the inventory then establishes, per
capability slot (**autofix** / **diagnostic**, as the lane registry defines
them), which recognized provider — if any — the project already has. Three
signal classes, still cheap and deterministic — no builds, no network:
1. **Config-file signals** — `eslint.config.js`/`.eslintrc*`, `biome.json`,
`[tool.ruff]`/`[tool.black]`/`[tool.mypy]` sections in `pyproject.toml`,
`.flake8`/`setup.cfg` sections, `.pylintrc`, `checkstyle.xml`, PMD
rulesets (`pmd-ruleset.xml`).
2. **Dependency signals** — `package.json` devDependencies,
`requirements-dev.txt`/the `pyproject.toml` dev group, Maven/Gradle
plugin blocks.
3. **Executable probes** — the lane registry's detection probes, run per
candidate provider down each slot's ordered provider list
(`tool-configs.md` § Build-time lanes; repo-local locations first,
then PATH).
Binding follows **bind-don't-replace**: an existing, configured tool that
passes the qualification contract is bound as its slot's provider, and the
plugin's default is never installed over it. A bound equivalent — black +
flake8 as a pair, biome, an ESLint kept under demotion, checkstyle —
satisfies its slot; nothing is installed for it.
### Step 3: Confirm the three-column plan
Detection is always confirmed, never assumed. Present the stack + inventory
results as a three-column plan and wait for the user to confirm it
**before any file is written or any install runs** (**under `--yes`, print the
plan and proceed without waiting** — see the Arguments section):
1. **Found and keeping** — providers the inventory bound. Nothing is
installed for these slots, and existing configs (`eslint.config.js`,
`pyproject.toml` sections, `.editorconfig`, …) are never overwritten —
this column doubles as the report of what already exists and is left
alone.
2. **Missing and will add** — empty slots to be filled with the lane's
default tool. **Only this column installs anything.**
3. **Found but can't participate** — a present tool that fails the
qualification contract (e.g. pyright before its adapter exists), with
the reason stated and the lane default offered alongside — never a
silent replacement.
The mode follows from what detection found:
- **Existing project** (sources present) → tools-only mode, driven entirely
by the three columns: bind, fill empty slots, surface non-conforming
tools. No existing config file is modified.
- **Greenfield JS/TS** (empty or near-empty dir) → the full scaffold below;
its defaults are presented as this plan's **missing and will add**
column.
- **Greenfield Python/C#/Java** → tools plus minimal config (full
config-scaffold parity with the JS path lands as per-language
follow-ups).
### Step 4: Install missing tools (repo-level, per lane)
Every install lands in the project, versioned with it, reproducible for
every contributor and CI — never `pip install --user`, never a global
pipx install, never `npm install -g`.
- **JS/TS** — greenfield: the full scaffold below (oxlint as the default
linter, ESLint behind `lint:deep`). Existing project: fill the empty
autofix slot as a devDependency, leaving all configs alone:
```bash
npm install --save-dev oxlint
```
If this fails with `npm error code ERESOLVE`, the peer conflict is
pre-existing in the repo's tree (not with `oxlint`) — retry once with
`--legacy-peer-deps` and note to the user that you did so, rather than
aborting.
- **Python** — add `ruff` and `mypy` — plus `pytest` if no test runner is
present — to the project's own dev-dependency mechanism: the
`pyproject.toml` dev group or `requirements-dev.txt`, whichever the
project already uses; create `requirements-dev.txt` if neither exists.
- **C#** — nothing to install: both lane tools ship with the .NET SDK.
Verify the SDK is present — honoring a `global.json` pin when one
exists — and that `dotnet format --version` responds.
- **Java** — verify a JDK is present (`java` on PATH), then run the
plugin's pinned-PMD installer — the user never locates or invokes it by
hand:
```bash
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/install-java-static-analysis.py"
```
It installs a pinned PMD distribution into the repo-local, gitignored
`.pmd/` directory (version pin single-sourced in the script; re-runs are
idempotent). Add the `.pmd/` entry to the project's `.gitignore` if it
is missing.
### Step 4b: Install capability tools
Beyond the four static-analysis lanes, other skills and agents depend on a
set of **capability tools**. `references/capability-tools.md` is their single
source of truth — a registry of *tool | skills that need it | offer-when
signal | OS-aware install command | verify probe*. This step installs the
warranted ones so the "run `/project-init`" pointer those skills print is
honest.
**Run the detection signals** (cheap, deterministic — no builds, no network):
| Capability | Skills served | Offer-when signal |
|---|---|---|
| semgrep | `/semgrep-analyze`, security-assessment | any source lane detected (universal SAST) — always offer, opt-in |
| Playwright + Chromium | `/benchmark`, `/browse`, `/browser-testing`, `/performance-benchmark` | frontend signals (React/Svelte/Vue/Angular/Next/Nuxt/SvelteKit/Astro, or an `e2e/` dir, or `playwright.config.*`) in an existing project |
| adr | `/adr-tools`, adr-author | `docs/adr/`, `docs/decisions/`, or existing ADR `*.md` files present |
| gh | `/issues-from-assessment` and other issue/PR skills | git repo with a GitHub remote (`git remote -v` shows `github.com`) |
| docker scanners (hadolint, trivy, grype) | `/docker-image-audit` | a `Dockerfile`/`*.dockerfile`/`compose.y*ml` present |
**Present the warranted capability tools as their own group** in the Step 3
three-column plan — a "capability tools" block alongside the lane columns —
and **confirm before installing**, same gate as the lanes. **Under `--yes`,
install every warranted-and-missing tool without prompting** (see the
Arguments section). Install only the
tools whose signal fired *and* that the user confirmed *and* that are still
missing (skip any already on `PATH`). Use the OS-aware install command from
`references/capability-tools.md` for each — never inline a different command.
**Install-level honesty.** The "always repo-level, never user/system" rule
of the lanes applies to the lane tools **plus Playwright**. The other
capability tools are general-purpose CLIs that are **user/system-level by
nature** — there is no repo-local install for `gh`, `semgrep`, `adr`, or the
docker scanners, so they install via the OS package manager (or pipx / user
pip on Linux). **Playwright is the repo-level exception among capability
tools**: it installs as an `npm` devDependency (`@playwright/test`), versioned
with the project like a lane tool — only its Chromium download is machine-level.
State this explicitly to the user when the capability group installs. If the
Playwright `npm` install fails with `npm error code ERESOLVE`, the peer
conflict is pre-existing in the repo's tree (`@playwright/test` has no
framework peer relationship) — retry that install once with
`--legacy-peer-deps` and note to the user that you did so, rather than
aborting.
### Step 4c: Offer the code-lookup tools (keyless group + keyless Graphify build)
Three optional, complementary code-intelligence tools — **CodeGraph**,
**Repowise**, and **Graphify** — let the review and analysis agents read
verified skeletons, resolved call graphs, modification risk, and decision
rationale instead of re-reading whole files. None is required.
They are offered by **cost profile**, so the operator never has to accept a
model/API-key cost to get the keyless tools (issue #1141, which relaxes the
single all-or-none group of #1108):
- **Keyless pair — CodeGraph + Repowise.** Both build a purely structural
index with **no model/API key** and are safe to build unattended. They are
offered as **one all-or-none group** — a single decision that gives the
agents a consistent, predictable lookup set (issue #1108). Accepting the
group both **installs and builds** every missing tool's index in this same
run — it is not a "print instructions and leave it to the user" step (issues
#1134, #1135). CodeGraph installs its CLI (`npm install -g
@colbymchenry/codegraph`) and runs `codegraph init .`; Repowise installs and
runs `repowise init . --no-prose -y` for a keyless index.
- **Graphify — full extraction is the target; `--code-only` is a degraded
Auf GitHub ansehen