wise-init · git:20260725.7dfa442 · 2026-07-25 · sha256 26c5f0d93d009aab
wise-init git:20260725.7dfa442A
Immutable. This exact content is served forever at /api/v1/blob/26c5f0d93d009aab.
---
name: wise-init
description: >-
First-time setup wizard — walk the user through installing wise's
system deps (Python 3 + pyyaml/ulid/typing_extensions, Node ≥22, gh
CLI + `gh auth login`, markitdown for file-to-markdown extraction)
and cache the probe results so workflow runs skip the live check.
Idempotent — re-running only prompts for gaps.
Invoked as `/wise-init` (bare alias) or `/wise:wise-init` (canonical).
Use when the user says "init wise", "set up wise", "install wise deps",
"first-time setup", "run the setup wizard", or types `/wise-init`.
argument-hint: ""
allowed-tools: Read, AskUserQuestion, Bash(bash:*), Bash(python3:*), Bash(printf:*), Bash(test:*), Bash(cat:*), Bash(uv:*), Bash(mise exec:*)
---
# /wise-init — first-time setup wizard
## Why this skill exists
Before 0.41.0, every workflow-adjacent wise skill ran
`scripts/bootstrap-deps.sh` as its first step — probing Python,
Node, and the gh CLI on every invocation. That was correct but
slow on the hot path and clumsy for fresh installs: the user got
piecemeal "install X, now install Y, now `gh auth login`" across
successive skill invocations instead of one guided walkthrough.
`/wise-init` is that walkthrough. It probes each dep in turn, shows
installer options with exact commands to paste when something's
missing, pauses for the user to run them, re-probes, and finally
writes a registry file the workflow engine consumes as a
fast-path on every subsequent run. Re-runs are cheap — the wizard
skips deps that are already present.
**The registry lives at `${CLAUDE_PLUGIN_ROOT}/.wise-init-registry.yaml`.**
That's inside the plugin install dir on purpose — it gets wiped on
every `/plugin install wise@…`, which is exactly the invalidation
signal we want: "the plugin updated, something new might be
required, user should re-init".
## Arguments
This skill takes no arguments. Ignore anything the user types beyond
the skill name.
## Procedure
### 1. Preamble
Print one short paragraph to the user introducing the flow. Keep
it under 4 lines:
```
First-time setup. I'll walk you through the system deps wise needs —
Python 3, Node ≥22, the gh CLI (with auth), and markitdown (file →
markdown text extraction). Re-runs are safe: I skip what's already
installed. After this I cache the probe results so future workflow
runs skip the live check.
```
### 2. Python (and its pip modules)
**2a. Probe.**
```bash
bash "${CLAUDE_PLUGIN_ROOT}/scripts/init.sh" probe-python
```
The probe emits **bare** `KEY=VALUE` lines — `STATUS`, `BINARY`,
`VERSION`, `MODULE_YAML`, `MODULE_ULID`, `MODULE_TYPING_EXTENSIONS`
(all three probes reuse the same bare key names by design; see
`init.sh`). Read them into per-dep Claude-side variables — referred
to below as `PY_STATUS`, `PY_BINARY`, `PY_VERSION`, `PY_MODULE_*`.
**2b. Handle the result.**
- **`PY_STATUS=ok` and all modules `ok`:** print one line
`Python <ver> ✓ at <binary>` and move to §3. No AskUserQuestion
needed — this is the happy path.
- **`PY_STATUS=ok` but at least one module is `missing`:** offer to
pip-install the missing ones. `AskUserQuestion`:
- Question: `Python <ver> is installed but these modules are missing: <list>. Install them now?`
- Header: `pip install`
- Options:
- `Install (recommended)` — description: `Run: <PY_BINARY> -m pip install --user <missing pkgs>`
- `Skip` — description: `Continue without these modules. wise's workflow engine will fail with an import error later.`
- multiSelect: false
On `Install`: run
```bash
"<PY_BINARY>" -m pip install --user --quiet pyyaml python-ulid typing_extensions
```
(substituting the mapping: `yaml → pyyaml`, `ulid → python-ulid`,
`typing_extensions → typing_extensions`; only include the ones
that were `missing`). Re-probe via §2a.
**If pip exits with `error: externally-managed-environment` (PEP 668)** —
almost always the case when `<PY_BINARY>` is the Homebrew system
Python on macOS — do NOT silently fall back to
`--break-system-packages`. Instead, pivot the user onto
mise-managed Python, which doesn't have the lockdown:
- `AskUserQuestion`:
- Question: `pip refused to install into <PY_BINARY> because of PEP 668 (externally-managed-environment). The recommended fix is to install a user-owned Python via mise — it sidesteps the lockdown and pins per-project versions cleanly. How would you like to proceed?`
- Header: `pip-failed`
- Options:
- `Install Python via mise (recommended)` — description: `brew install mise && mise use -g python@latest, then re-probe. The re-probe should pick up the mise-managed interpreter, and pip --user works against it.`
- `Override with --break-system-packages` — description: `Run: <PY_BINARY> -m pip install --user --break-system-packages <missing pkgs>. Escape hatch — packages can get stranded if brew upgrades the underlying Python.`
- `Abort init` — description: `Stop here; resolve manually and re-run /wise-init.`
- multiSelect: false
On `Install Python via mise`: print the two-line install block
and pause for the user to run them in their terminal, then jump
to the `Done — re-probe` follow-up below (same shape as the
`PY_STATUS=missing` path). On `Override`: run the
`--break-system-packages` invocation and re-probe via §2a.
On `Abort`: stop with a one-line summary.
If after the chosen path any module is still missing, surface
the pip error and `Abort init`.
- **`PY_STATUS=missing`:** `AskUserQuestion`:
- Question: `Python 3 isn't installed. How would you like to install it? mise is strongly recommended — it gives you a user-owned Python that pip --user can write into (no PEP 668 lockdown) and lets you pin versions per project.`
- Header: `Install Python`
- Options:
- `mise (strongly recommended)` — description: `brew install mise && mise use -g python@latest. Sidesteps the PEP 668 lockdown that bites Homebrew system Python on macOS.`
- `brew (system Python)` — description: `brew install python@3. Works, but pip install --user will hit "externally-managed-environment" — you'll have to use --break-system-packages or a venv for every install.`
- `Manual` — description: `I'll install Python myself — hold the wizard until I'm done.`
- multiSelect: false
Whichever the user picks, the wizard's job is just to wait for
them to run the commands in their own terminal. Claude doesn't
run the installer — we can't `brew install` a new binary from
inside a skill. After the user picks, print:
```
Run the commands above in your terminal, then reply "done" (or
use the "Done — re-probe" option below).
```
Then a follow-up `AskUserQuestion`:
- Options: `Done — re-probe` / `Abort init`.
On `Done — re-probe`: re-run §2a. Up to 2 retries total; on the
third miss offer `Abort init` or continue anyway.
**2c. Record.**
Once §2b terminates with Python usable (or the user explicitly
chose to proceed without it), hold a Python result object in
Claude-side state:
```json
{
"status": "ok" | "missing",
"binary": "<PY_BINARY or empty>",
"version": "<PY_VERSION or empty>",
"modules": {
"yaml": "ok" | "missing",
"ulid": "ok" | "missing",
"typing_extensions": "ok" | "missing"
}
}
```
### 3. Node ≥22
Same pattern as §2, but with `init.sh probe-node`. Bare keys
`STATUS`, `BINARY`, `VERSION`, `MAJOR` → `NODE_STATUS`,
`NODE_BINARY`, `NODE_VERSION`, `NODE_MAJOR`.
- **`NODE_STATUS=ok`:** print `Node <ver> ✓ at <binary>` and move on.
- **`NODE_STATUS=too-old`:** `AskUserQuestion`:
- Question: `Detected Node <ver> at <binary>, but wise needs Node 22+. How would you like to upgrade?`
- Options:
- `mise (recommended)` — description: `mise use -g node@22`
- `brew` — description: `brew install node@22 && brew link --overwrite --force node@22`
- `Manual` — description: `I'll upgrade Node myself — hold the wizard.`
Same `Done — re-probe` loop as §2b.
- **`NODE_STATUS=missing`:** same install options, but `brew install node` (no `@22` clause since there's nothing to upgrade from).
Record:
```json
{"status": "ok" | "missing", "binary": "...", "version": "..."}
```
### 4. gh CLI + auth
**4a. Probe.**
```bash
bash "${CLAUDE_PLUGIN_ROOT}/scripts/init.sh" probe-gh
```
Bare keys `STATUS`, `BINARY`, `VERSION`, `AUTHENTICATED`, `LOGIN`
→ `GH_STATUS`, `GH_BINARY`, `GH_VERSION`, `GH_AUTHENTICATED`,
`GH_LOGIN`.
**4b. Binary check.**
- **`GH_STATUS=missing`:** offer install options:
- `brew (recommended)` — description: `brew install gh`
- `mise` — description: `mise use -g gh@latest`
- `Manual`
Same `Done — re-probe` loop. On success, continue to §4c.
**4c. Auth check.**
Once the gh binary is present, check `GH_AUTHENTICATED`:
- **`GH_AUTHENTICATED=true`:** print
`gh <ver> ✓ (authenticated as <GH_LOGIN>)` and move on.
- **`GH_AUTHENTICATED=false`:** `AskUserQuestion`:
- Question: `gh is installed but not authenticated. Run "gh auth login" in your terminal to complete the browser flow.`
- Header: `gh auth`
- Options:
- `Done — re-probe` — user ran `gh auth login`; re-probe and check.
- `Skip auth for now` — description: `Continue without authentication. wise-pr-* skills and any workflow step that hits the GitHub API will fail until you run gh auth login.`
Re-probe after `Done`. After 2 failed attempts, offer to skip.
Record:
```json
{
"status": "ok" | "missing",
"binary": "...",
"version": "...",
"authenticated": true | false,
"login": "<handle or empty>"
}
```
### 5. markitdown (file → markdown extraction)
The [`markitdown`](https://github.com/microsoft/markitdown) CLI powers
the `wise-markitdown` reference skill — text extraction from PDF /
DOCX / XLSX / PPTX / images / audio / EPUB / ZIP / … to markdown.
Optional in the sense that no workflow engine step needs it, but the
extraction skill degrades to one-shot `uvx` runs without it, so the
wizard installs it properly here.
**5a. Probe.**
```bash
bash "${CLAUDE_PLUGIN_ROOT}/scripts/init.sh" probe-markitdown
```
Bare keys `STATUS`, `BINARY`, `VERSION`, `UV` → `MD_STATUS`,
`MD_BINARY`, `MD_VERSION`, `MD_UV`. `UV` reports whether the `uv`
installer is reachable (directly or via mise) — it is emitted even
when markitdown itself is already installed.
**5b. Handle the result.**
- **`MD_STATUS=ok`:** print `markitdown <ver> ✓ at <binary>` and move
to §6. (The probe can't tell a bare `markitdown` install from a
`markitdown[all]` one — if conversions later fail with
`MissingDependencyException`, the fix is
`uv tool install --force 'markitdown[all]'`; the `wise-markitdown`
skill documents this.)
- **`MD_STATUS=missing` and `MD_UV=ok`:** `AskUserQuestion`:
- Question: `markitdown (file → markdown text extraction: PDF, DOCX, XLSX, PPTX, images, audio, …) isn't installed. Install it now via uv?`
- Header: `markitdown`
- Options:
- `Install (recommended)` — description: `Run: uv tool install 'markitdown[all]' — a user-space tool install, no sudo, no system Python touched.`
- `Skip` — description: `Continue without it. The wise-markitdown skill will fall back to one-shot uvx runs (re-downloads on a cold cache).`
- multiSelect: false
On `Install`: run
```bash
uv tool install 'markitdown[all]'
```
(when `uv` is only reachable through mise, run
`mise exec uv -- uv tool install 'markitdown[all]'` instead).
This IS run by the wizard — like the pip-module installs in §2b,
it's a user-space install with no sudo and no system packages.
Unpinned on purpose: wise tracks the latest release for every CLI
dep (gh, node, the pip modules) — markitdown follows the same
policy.
Re-probe via §5a; on success print the ✓ line. If the install
fails, surface the error and record `missing` — never retry blind.
- **`MD_STATUS=missing` and `MD_UV=missing`:** `uv` itself is absent,
so there's nothing for the wizard to run. `AskUserQuestion`:
- Question: `markitdown needs the uv installer, which isn't installed either. Install uv first?`
- Header: `uv missing`
- Options:
- `Install uv via mise (recommended)` — description: `Run in your terminal: brew install mise && mise use -g uv@latest — then I re-probe and install markitdown.`
- `Skip` — description: `Continue without markitdown. Re-run /wise-init after installing uv.`
- multiSelect: false
Like the §2b/§3 system installers, installing `uv`/`mise` is the
user's move — print the command, pause with the same
`Done — re-probe` / `Abort` follow-up, then resume the
`MD_UV=ok` branch above. On `Skip`, record `missing` and move on.
**5c. Record.**
```json
{"status": "ok" | "missing", "binary": "...", "version": "..."}
```
### 6. Write the registry
Compose a JSON object from the four result blobs above plus the
plugin version:
```json
{
"version": 1,
"plugin_version": "<contents of plugin.json's version field>",
"completed_at": "<utc ISO8601, see below>",
"deps": {
"python": { ... from §2c ... },
"node": { ... from §3 ... },
"gh": { ... from §4 ... },
"markitdown": { ... from §5c ... }
}
}
```
Read the plugin version:
```bash
python3 -c 'import json; print(json.load(open("'"${CLAUDE_PLUGIN_ROOT}"'/.claude-plugin/plugin.json"))["version"])'
```
Compute the timestamp:
```bash
date -u +%Y-%m-%dT%H:%M:%SZ
```
Then write the registry:
```bash
python3 "${CLAUDE_PLUGIN_ROOT}/scripts/init-registry.py" write '<the JSON blob>'
```
The script prints the registry path on stdout — capture that for
the summary.
### 7. Summary
Print a one-block report:
```
/wise-init complete.
Python 3.12.5 ✓
Node 22.20.0 ✓
gh 2.54.0 (auth: your-username) ✓
markitdown 0.1.3 ✓
Registry cached at:
${CLAUDE_PLUGIN_ROOT}/.wise-init-registry.yaml
Workflow runs (/wise-workflow-run, …) will use this cache instead
of re-probing. Re-run /wise-init any time your environment changes
or after `/plugin install wise@…` (which wipes the cache by design).
```
Adjust the row's checkmark to `⚠` and the label suffix when a dep
ended up `missing` or `authenticated: false`. Be honest — don't
claim success for something the user skipped.
## Guardrails
- **Never run a system installer for the user.** The wizard shows
the commands, the user pastes them in their own terminal. We can't
`brew install` / `mise use -g` from inside a skill (and wouldn't
want to — it prompts for sudo in some environments and changes the
user's `$PATH`). Our job is guidance + re-probe. The two sanctioned
exceptions are user-space package installs into an ALREADY-present
toolchain — `pip install --user` (§2b) and
`uv tool install` (§5b) — no sudo, no PATH mutation, and only
after an explicit AskUserQuestion confirm.
- **Never run `gh auth login` for the user.** It opens a browser
and requires a device code; the user has to be the one driving.
Pause with `Done — re-probe` and check `GH_AUTHENTICATED` after.
- **Never write anywhere but the registry path.** The registry
lives at `${CLAUDE_PLUGIN_ROOT}/.wise-init-registry.yaml` and
nowhere else. `init-registry.py write` enforces this.
- **Never block on a skipped dep.** Record the actual state
(`status: missing` or `authenticated: false`) and move on. The
workflow engine's fast-path check treats the registry as
ground truth — a dep recorded as `missing` tells the engine to
fall back to the live probe on use.
- **Never invoke another action skill from here.** `/wise-init` is a
standalone wizard — not composed over `wise-workflow-run` /
`wise-workflow-resume`.