Skip to content
Development
Command

/plan-workflow

PREVIEW (experimental) - autonomous /lets:plan via a Dynamic Workflow. Shipped standalone to dogfood across projects and gather edits before folding the chain into native /lets:plan.

From plugin
lets-workflow
1726 skills15 agents26 commands
> /plugin marketplace add restarter/lets-workflow
> /plugin install lets@lets-workflow

Command definition

plan-workflow.md
description: PREVIEW (experimental) - autonomous /lets:plan via a Dynamic Workflow. Shipped standalone to dogfood across projects and gather edits before folding the chain into native /lets:plan.
argument-hint: "[goal] [--fast]"

Autonomous Plan (PREVIEW workflow)

**PREVIEW / experimental.** Shipped standalone so the autonomous-planning Dynamic Workflow can be dogfooded across projects and gather edits before it's folded into native `/lets:plan --workflow` (tracked in lets-jsw00). The reusable artifact is `skills/plan-workflow/plan.workflow.js`; this command is a thin dispatcher. The interactive native `/lets:plan` is untouched. Expect rough edges - report them.

Autonomous whole-command planning: you give a GOAL + a RUBRIC up front; the workflow explores, proposes approaches, architects each, judges them against your rubric, evaluates the winner, and writes a plan - all off-context. You approve the plan at the end. **Steer-by-rubric + approve-at-end**, not gate-each-step.

> **IMPORTANT:** Deferred tools (e.g. `AskUserQuestion`) must be loaded and called as specified.

Step 0: Resolve & claim (spawn entry)

If the argument is an explicit **task id** - a single token matching the ACTIVE tracker's id shape per the **detect-task** convention (beads: `<prefix>-<alphanum>[.N]`; a numeric-id tracker: a pure-numeric id; do NOT hardcode the beads regex on a non-beads project) - rather than a free-text goal - as the autonomous pipeline launches it (`/lets:plan-workflow <id>` into a fresh worktree) - resolve-and-claim per the **detect-task** convention: treat the id as authoritative and, if the tracker's `show` reports `<id>` not `in_progress`, `Skill(skill: "lets:take-task", args: "<id>")` to claim it (the spawn-time entry claim is AUTO-MODE-exempt - see `detect-task/SKILL.md`). Then derive the GOAL from the task title + description for Step 1. A free-text goal argument skips this step (no claim). `--orc` is stripped per the detect-task convention before the task-id test.

Pipeline-state marker (spawn-claimed runs only)

When Step 0 spawn-claimed a task (the autonomous pipeline launched this), record the phase in a **per-task** marker so N parallel worktrees don't collide and the gate-notify can tell autonomous from interactive. **Per-task filename** (NOT a shared `pipeline-state` — `.lets/` is a symlink across worktrees): `.lets/cache/pipeline-state-<task-id>`, line `<task-id>|<phase>|<iso>`, phase ∈ `planning | gate-clarify | gate-approve | executing | blocked | done`. Helper:

LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel); mkdir -p "$LETS_PROJECT_ROOT/.lets/cache"
printf '%s|%s|%s\n' "{TASK_ID}" "{PHASE}" "$(date -u +%Y-%m-%dT%H:%M:%SZ)" > "$LETS_PROJECT_ROOT/.lets/cache/pipeline-state-{TASK_ID}"

plan-workflow writes `planning` at Step 3 (workflow launch), `gate-clarify` at GATE 1 (if clarify is needed), `gate-approve` at Step 4 (plan saved). An interactive (free-text-goal) run writes no marker → no gate notifications. **Keep in sync:** the same contract + helper live in `execute.md` (which writes `executing`/`blocked`/`done`).

Gate notifications (authoritative)

At a human gate, surface to the operator through the **active launcher** (`$LETS_LAUNCHER`) — **marker-gated** so only autonomous (spawn-claimed) runs notify; interactive runs have no marker and stay quiet. `lets notify` dispatches on `LETS_LAUNCHER` (cmux → cmux workspace, tmux → attached tmux clients, terminal → no-op) — never name a launcher in the snippet. Resolve the target by the worktree path:

LETS_PROJECT_ROOT=$(git rev-parse --show-toplevel)
if [ -f "$LETS_PROJECT_ROOT/.lets/cache/pipeline-state-{TASK_ID}" ]; then
  lets notify --cwd "$LETS_PROJECT_ROOT" --title '{gate title}' --body '{gate body}' --json 2>/dev/null || true
  [ "{LETS_LAUNCHER}" = "orca" ] && lets orca card --phase gate --comment '{gate title}' --json 2>/dev/null || true
fi

**Quoting:** the substituted values (`{gate title}`, `{gate body}` — the latter carries the user-authored task title) go in **single quotes**, so a title containing `$(...)`, backticks, or `$VAR` is a literal, not shell-expanded, before it reaches the injection-safe CLI. Only `$LETS_PROJECT_ROOT` stays double-quoted (it's a real shell var). If a substituted value contains a literal `'`, the orchestrator escapes it (`'\''`) when building the command. Degrades silently (`ok=true, notified=false`) when the launcher is `terminal`, unknown, its binary is absent, or nothing matches (tmux with no client attached → `no_client`); `|| true` covers the non-unix stub. The notification is **best-effort surfacing** — the gate also halts visibly in-band; never rely on it alone. Gates: **GATE 1** "Plan needs your answers" (clarify), **GATE 2** "Plan ready to approve". **Keep in sync:** `execute.md` reuses this block for its execute-blocked notify.

Step 1: Goal + Rubric

Parse the goal from the argument (or, for a spawn-claimed task, from its title + description; else ask "What are we planning?"). Strip a `--fast` token anywhere in the argument if present (sets lean/fast mode for this run); the remainder is the goal OR the task id. The strip happens at INITIAL argument parsing - BEFORE Step 0's task-id pattern match - so `/lets:plan-workflow <task-id> --fast` (the natural autonomous-pipeline invocation) still resolve-and-claims: only the flag-stripped remainder is tested against the active tracker's id shape (Step 0). Mirror how native `/lets:plan` strips `--fast` - but note the two flags mean DIFFERENT things (see `## Fast mode` below).

Gather the **RUBRIC** - the steering criteria that REPLACE the interactive picks of native `/lets:plan`. Ask the user (free text, or a short list):

  • What does "good" look like here? (priority order: simplicity / performance / consistency / minimal-blast-radius / ...)
  • Hard constraints (must-not-break, must-not-touch, compatibility).
  • Scope boundaries (explicitly OUT).
  • Success criteria.

**Do not proceed withou

Read more
@restarter
Ships withlets-workflow

A development workflow plugin for Claude Code Stop babysitting your AI. Start shipping with it.

1725 skills15 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
17
Star history of restarter/lets-workflow on GitHub, a chart by star-history.com

Other commands on lets-workflow.

backlog

backlog

Command

Backlog review and cleanup - multi-agent backlog review, quick no-agent pulse (--fast), or interactive triage cleanup

end

end

Command

End a work session - a settlement pass that reconciles uncommitted / unpushed work + session context into git, the tracker, and a…

execute

execute

Command

Execute implementation plan from /lets:plan - inline in native plan mode, or delegated to named implementer subagents you review…

More commands from other plugins.

build
Auto-invoked

build

Command

Implement tasks incrementally — build, test, verify, commit. Add "auto" to run the whole plan in one approved pass.

@addyosmani@addyosmaniInstall Command