/init
Initialize LETS in current project - creates .lets/ structure, config, statusline, beads; offers user-scope global-rules install when the plugin is user-scoped
$ npx -y skills add restarter/lets-workflow --agent claude-codeHow it fires
How this command gets triggered: by you, by Claude, or both.
- Fires itselfClaude auto-loads it when your prompt matches the work.
- You can call itInvoke it directly when you want it.
- Slash command
/init
Context preview
What this command does when you run it.
Initialize LETS in current project - creates .lets/ structure, config, statusline, beads; offers user-scope global-rules install when the plugin is user-scoped
Command definition
init.mddescription: Initialize LETS in current project - creates .lets/ structure, config, statusline, beads; offers user-scope global-rules install when the plugin is user-scoped
Project Initialization
Per-project LETS setup. Bridges to `lets init --json` (Go binary) for all filesystem mutation. Slash command captures user prefs via AskUserQuestion, exec's the binary, parses JSON stdout, renders to user.
> **IMPORTANT:** If the spec below invokes any deferred tool (e.g. `AskUserQuestion`), you MUST load and call it as specified. Never skip the call, never substitute a default answer of your own — the tool invocation is part of the contract. This is critical.
> **MANDATORY:** Execute every Step's bash block **literally as written**. Do not substitute output from earlier `ls`/`cat`/`bd show` in this conversation — `.env` and other dotfiles are invisible to plain `ls`. The `test -f` / `test -d` checks below ARE the contract for branching first-time-vs-re-run paths; shortcutting them produces wrong branches.
Step 1: Pre-checks
command -v lets >/dev/null 2>&1 || { echo "NO_LETS_BINARY"; exit 0; }
LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || echo "NOT_GIT_REPO"
if [ -n "$LETS_PROJECT_ROOT" ]; then
test -f "$LETS_PROJECT_ROOT/.lets/.env" && echo "ENV_EXISTS" || echo "ENV_ABSENT"
test -d "$LETS_PROJECT_ROOT/.beads" && echo "BEADS_EXISTS" || echo "BEADS_ABSENT"
fiBranch on output:
- `NO_LETS_BINARY` → tell user "`lets` binary not found on `$PATH`. Install it — `! curl -fsSL https://raw.githubusercontent.com/restarter/lets-workflow/main/scripts/install.sh | bash` (the leading `!` runs it in this session; or the same command without `!` in a terminal). See the README → Quick Start." NO LETS box. STOP.
- `NOT_GIT_REPO` → ask user via AskUserQuestion (Step 1a below). If user picks "Init git" → run `git init`, recompute LETS_PROJECT_ROOT, ENV_ABSENT/BEADS_ABSENT (both will be absent for fresh repo). If "Cancel" → stop, NO LETS box.
- `ENV_ABSENT` → first-time path (Step 2). Use `BEADS_ABSENT`/`BEADS_EXISTS` to decide whether to ask about beads init in Step 2c-bis.
- `ENV_EXISTS` → re-run path (Step 3). Don't re-ask about beads — `lets init` self-heals (StepSkip if already inited; StepWarn if bd not on PATH).
1a. Git init prompt (only if NOT_GIT_REPO)
AskUserQuestion( questions=[{ question: "This directory is not a git repository. Initialize git here?", header: "Git init", options: [ { label: "Init git", description: "Run `git init` here, then continue with this init flow (LETS workflow assumes git)" }, { label: "Cancel", description: "Stop. Run `git init` manually first or cd to a git repo." } ], multiSelect: false }] )
If "Init git":
git init -q
LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel)
Then proceed with first-time path (ENV_ABSENT, BEADS_ABSENT both true for fresh repo).
If "Cancel" → STOP. NO LETS box.
1b. Plugin install scope check
PLUGINS_FILE="$HOME/.claude/plugins/installed_plugins.json"
SCOPE=""
if [ -f "$PLUGINS_FILE" ] && command -v python3 >/dev/null 2>&1; then
SCOPE=$(python3 -c "
import json, sys
try:
d = json.load(open('$PLUGINS_FILE'))
entries = d.get('plugins', {}).get('lets@lets-workflow', [])
print(entries[0].get('scope', '') if entries else '')
except Exception:
pass
" 2>/dev/null)
fi
echo "SCOPE=${SCOPE:-unknown}"Branch on `$SCOPE`. When the plugin is found (`project` / `user` / `local`) **lead** with the **auto-update recommendation** - this is the single biggest update-UX win, so present it prominently (not as a footnote): > ✅ **Do this once - it removes the manual plugin update forever:** `/plugin` → **Marketplaces** → `lets-workflow` → **Enable auto-update**. The plugin then tracks every LETS release on its own, so ongoing updates collapse to a single `/lets:update` loop (run it, do the one thing it says, re-run until `✓ Everything on vX.Y.Z`) - no `/plugin marketplace update` step to remember. (Claude Code has no setting the `lets` binary can flip - this is a one-time UI action only you can do.)
Additionally:
- `project` → just the auto-update recommendation. Best case.
- `user` → the auto-update recommendation **plus** the global-rules check:
test -f "$HOME/.claude/rules/lets-rules.md" && echo "GLOBAL_RULES_PRESENT" || echo "GLOBAL_RULES_ABSENT"
- `GLOBAL_RULES_PRESENT` → one line: "ℹ️ User-scope install detected — global rules active (`~/.claude/rules/lets-rules.md`); `/lets:update` keeps them current." Continue.
- `GLOBAL_RULES_ABSENT` → offer the install (AskUserQuestion, header `User scope`):
- "Install global rules (Recommended)" - description: "Writes ~/.claude/rules + ~/.lets/.env defaults; every project gets LETS rules without per-project init"
- "Project-only" - description: "Skip global install; this project gets its own rules copy below"
If installed → run, then render its `steps[]` like Step 2e renders project steps:
lets init --user --json --plugin-root="${CLAUDE_PLUGIN_ROOT}" --language="{LANGUAGE}"(`{LANGUAGE}` is an orchestrator placeholder — substitute the English language name BEFORE running. If no language is bound yet (Step 2a hasn't run), ask Step 2a's language question first. NEVER leave a bash variable here: `$LANG` is the POSIX locale env var (`en_US.UTF-8`) and bash would expand it, silently poisoning `~/.lets/.env` in every future session. Add `--launcher={LAUNCHER}` only if the user customized the launcher this session.)
- One-line note stays for teams: "For team adoption, project scope is still preferable (`/plugin install` → 'all collaborators')."
- `local` → just the auto-update recommendation. User picked the scope deliberately, so no scope-change notice.
- `unknown` (empty / file missing / dev `--plugin-dir` mode) → no notice at all.
These are informational, not blockers. Continue with Step 2/3 regardless.
Step 2: F
Read more
description: Initialize LETS in current project - creates .lets/ structure, config, statusline, beads; offers user-scope global-rules install when the plugin is user-scoped
Project Initialization
Per-project LETS setup. Bridges to `lets init --json` (Go binary) for all filesystem mutation. Slash command captures user prefs via AskUserQuestion, exec's the binary, parses JSON stdout, renders to user.
> **IMPORTANT:** If the spec below invokes any deferred tool (e.g. `AskUserQuestion`), you MUST load and call it as specified. Never skip the call, never substitute a default answer of your own — the tool invocation is part of the contract. This is critical.
> **MANDATORY:** Execute every Step's bash block **literally as written**. Do not substitute output from earlier `ls`/`cat`/`bd show` in this conversation — `.env` and other dotfiles are invisible to plain `ls`. The `test -f` / `test -d` checks below ARE the contract for branching first-time-vs-re-run paths; shortcutting them produces wrong branches.
Step 1: Pre-checks
command -v lets >/dev/null 2>&1 || { echo "NO_LETS_BINARY"; exit 0; }
LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel 2>/dev/null) || echo "NOT_GIT_REPO"
if [ -n "$LETS_PROJECT_ROOT" ]; then
test -f "$LETS_PROJECT_ROOT/.lets/.env" && echo "ENV_EXISTS" || echo "ENV_ABSENT"
test -d "$LETS_PROJECT_ROOT/.beads" && echo "BEADS_EXISTS" || echo "BEADS_ABSENT"
fiBranch on output:
- `NO_LETS_BINARY` → tell user "`lets` binary not found on `$PATH`. Install it — `! curl -fsSL https://raw.githubusercontent.com/restarter/lets-workflow/main/scripts/install.sh | bash` (the leading `!` runs it in this session; or the same command without `!` in a terminal). See the README → Quick Start." NO LETS box. STOP.
- `NOT_GIT_REPO` → ask user via AskUserQuestion (Step 1a below). If user picks "Init git" → run `git init`, recompute LETS_PROJECT_ROOT, ENV_ABSENT/BEADS_ABSENT (both will be absent for fresh repo). If "Cancel" → stop, NO LETS box.
- `ENV_ABSENT` → first-time path (Step 2). Use `BEADS_ABSENT`/`BEADS_EXISTS` to decide whether to ask about beads init in Step 2c-bis.
- `ENV_EXISTS` → re-run path (Step 3). Don't re-ask about beads — `lets init` self-heals (StepSkip if already inited; StepWarn if bd not on PATH).
1a. Git init prompt (only if NOT_GIT_REPO)
AskUserQuestion( questions=[{ question: "This directory is not a git repository. Initialize git here?", header: "Git init", options: [ { label: "Init git", description: "Run `git init` here, then continue with this init flow (LETS workflow assumes git)" }, { label: "Cancel", description: "Stop. Run `git init` manually first or cd to a git repo." } ], multiSelect: false }] )
If "Init git":
git init -q LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel)
Then proceed with first-time path (ENV_ABSENT, BEADS_ABSENT both true for fresh repo).
If "Cancel" → STOP. NO LETS box.
1b. Plugin install scope check
PLUGINS_FILE="$HOME/.claude/plugins/installed_plugins.json"
SCOPE=""
if [ -f "$PLUGINS_FILE" ] && command -v python3 >/dev/null 2>&1; then
SCOPE=$(python3 -c "
import json, sys
try:
d = json.load(open('$PLUGINS_FILE'))
entries = d.get('plugins', {}).get('lets@lets-workflow', [])
print(entries[0].get('scope', '') if entries else '')
except Exception:
pass
" 2>/dev/null)
fi
echo "SCOPE=${SCOPE:-unknown}"Branch on `$SCOPE`. When the plugin is found (`project` / `user` / `local`) **lead** with the **auto-update recommendation** - this is the single biggest update-UX win, so present it prominently (not as a footnote): > ✅ **Do this once - it removes the manual plugin update forever:** `/plugin` → **Marketplaces** → `lets-workflow` → **Enable auto-update**. The plugin then tracks every LETS release on its own, so ongoing updates collapse to a single `/lets:update` loop (run it, do the one thing it says, re-run until `✓ Everything on vX.Y.Z`) - no `/plugin marketplace update` step to remember. (Claude Code has no setting the `lets` binary can flip - this is a one-time UI action only you can do.)
Additionally:
- `project` → just the auto-update recommendation. Best case.
- `user` → the auto-update recommendation **plus** the global-rules check:
test -f "$HOME/.claude/rules/lets-rules.md" && echo "GLOBAL_RULES_PRESENT" || echo "GLOBAL_RULES_ABSENT"
- `GLOBAL_RULES_PRESENT` → one line: "ℹ️ User-scope install detected — global rules active (`~/.claude/rules/lets-rules.md`); `/lets:update` keeps them current." Continue.
- `GLOBAL_RULES_ABSENT` → offer the install (AskUserQuestion, header `User scope`):
- "Install global rules (Recommended)" - description: "Writes ~/.claude/rules + ~/.lets/.env defaults; every project gets LETS rules without per-project init"
- "Project-only" - description: "Skip global install; this project gets its own rules copy below"
If installed → run, then render its `steps[]` like Step 2e renders project steps:
lets init --user --json --plugin-root="${CLAUDE_PLUGIN_ROOT}" --language="{LANGUAGE}"(`{LANGUAGE}` is an orchestrator placeholder — substitute the English language name BEFORE running. If no language is bound yet (Step 2a hasn't run), ask Step 2a's language question first. NEVER leave a bash variable here: `$LANG` is the POSIX locale env var (`en_US.UTF-8`) and bash would expand it, silently poisoning `~/.lets/.env` in every future session. Add `--launcher={LAUNCHER}` only if the user customized the launcher this session.)
- One-line note stays for teams: "For team adoption, project scope is still preferable (`/plugin install` → 'all collaborators')."
- `local` → just the auto-update recommendation. User picked the scope deliberately, so no scope-change notice.
- `unknown` (empty / file missing / dev `--plugin-dir` mode) → no notice at all.
These are informational, not blockers. Continue with Step 2/3 regardless.
Step 2: F
A development workflow plugin for Claude Code Stop babysitting your AI. Start shipping with it.
Other commands on lets-workflow.
- /ask
Ask a single expert agent a question - like a Slack ping to a colleague
Open command - /backlog
Backlog review and cleanup - multi-agent backlog review, quick no-agent pulse (--fast), or interactive triage cleanup
Open command - /check
Quick sanity check - code (inline 6-perspective) or plan (--plan).
Open command - /done
Finish a task - document, create PR or merge, close
Open command - /end
End a work session - a settlement pass that reconciles uncommitted / unpushed work + session context into git, the tracker, and a session snapshot file. --pre-compact skips settlement and only writes the shared snapshot, keeping the session going.
Open command - /execute
Execute implementation plan from /lets:plan - load plan and enter native plan mode
Open command

