Workflow-Lite-Plan
Planning pipeline: explore → clarify → plan → confirm → handoff to lite-execute.
Context Isolation
CRITICAL: If invoked from analyze-with-file (via "执行任务"), the analyze-with-file session is COMPLETE and all its phase instructions are FINISHED and MUST NOT be referenced. Only follow LP-Phase 1-5 defined in THIS document. Phase numbers are INDEPENDENT of any prior workflow.
Input
<task-description> Task description or path to .md file (required)
Flag Description
-y , --yes
Auto mode: Skip clarification, auto-confirm plan, auto-select execution, skip review (entire plan+execute workflow)
--force-explore
Force code exploration even when task has prior analysis
Note: Workflow preferences (autoYes , forceExplore ) must be initialized at skill start. If not provided by caller, skill will prompt user for workflow mode selection.
Output Artifacts
Artifact Description
exploration-{angle}.json
Per-angle exploration results (1-4 files based on complexity)
explorations-manifest.json
Index of all exploration files
planning-context.md
Evidence paths + synthesized understanding
plan.json
Plan overview with task_ids[] (plan-overview-base-schema.json)
.task/TASK-*.json
Independent task files (one per task)
Output Directory: .workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/
Agent Usage: Low → Direct Claude planning (no agent) | Medium/High → cli-lite-planning-agent
Schema Reference: ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json
Auto Mode Defaults
When workflowPreferences.autoYes === true (entire plan+execute workflow):
- Clarification: Skipped | Plan Confirmation: Allow & Execute | Execution: Auto | Review: Skip
Auto mode authorizes the complete plan-and-execute workflow with a single confirmation. No further prompts.
Phase Summary
Phase Core Action Output
LP-0 Initialize workflowPreferences autoYes, forceExplore
LP-1 Complexity assessment → parallel cli-explore-agents (1-4) exploration-*.json + manifest
LP-2 Aggregate + dedup clarification_needs → multi-round AskUserQuestion clarificationContext (in-memory)
LP-3 Low: Direct Claude planning / Medium+High: cli-lite-planning-agent plan.json + .task/TASK-*.json
LP-4 Display plan → AskUserQuestion (Confirm + Execution + Review) userSelection
LP-5 Build executionContext → Skill("lite-execute") handoff (Mode 1)
Implementation
LP-Phase 0: Workflow Preferences Initialization
if (typeof workflowPreferences === 'undefined' || workflowPreferences === null) { workflowPreferences = { autoYes: false, // false: show LP-Phase 2/4 prompts | true (-y): skip all prompts forceExplore: false } }
LP-Phase 1: Intelligent Multi-Angle Exploration
Session Setup (MANDATORY):
const getUtc8ISOString = () => new Date(Date.now() + 8 * 60 * 60 * 1000).toISOString()
const taskSlug = task_description.toLowerCase().replace(/[^a-z0-9]+/g, '-').substring(0, 40)
const dateStr = getUtc8ISOString().substring(0, 10)
const sessionId = ${taskSlug}-${dateStr}
const sessionFolder = .workflow/.lite-plan/${sessionId}
bash(mkdir -p ${sessionFolder} && test -d ${sessionFolder} && echo "SUCCESS: ${sessionFolder}" || echo "FAILED: ${sessionFolder}")
TodoWrite Template (initial state — subsequent phases update status progressively):
// Pattern: set phases[0..N-1].status="completed", phases[N].status="in_progress"
// Only full block shown here; subsequent updates follow same structure with status changes
TodoWrite({ todos: [
{ content: LP-Phase 1: Exploration [${complexity}] ${selectedAngles.length} angles, status: "in_progress", activeForm: Exploring: ${selectedAngles.join(', ')} },
{ content: "LP-Phase 2: Clarification", status: "pending" },
{ content: LP-Phase 3: Planning [${planningStrategy}], status: "pending" },
{ content: "LP-Phase 4: Confirmation", status: "pending" },
{ content: "LP-Phase 5: Execution", status: "pending" }
]})
Exploration Decision Logic:
const hasPriorAnalysis = /##\s*Prior Analysis/i.test(task_description)
needsExploration = workflowPreferences.forceExplore ? true : hasPriorAnalysis ? false : (task.mentions_specific_files || task.requires_codebase_context || task.needs_architecture_understanding || task.modifies_existing_code)
if (!needsExploration) { // manifest absent; LP-Phase 3 loads with safe fallback proceed_to_next_phase() }
Context Protection: File reading >=50k chars → force needsExploration=true (delegate to cli-explore-agent)
Complexity Assessment:
const complexity = analyzeTaskComplexity(task_description) // 'Low': single file, single function, zero cross-module impact (fix typo, rename var, adjust constant) // 'Medium': multiple files OR integration point OR new pattern (add endpoint, implement feature, refactor) // 'High': cross-module, architectural, systemic (new subsystem, migration, security overhaul) // Default bias: uncertain between Low/Medium → choose Medium
const ANGLE_PRESETS = { architecture: ['architecture', 'dependencies', 'modularity', 'integration-points'], security: ['security', 'auth-patterns', 'dataflow', 'validation'], performance: ['performance', 'bottlenecks', 'caching', 'data-access'], bugfix: ['error-handling', 'dataflow', 'state-management', 'edge-cases'], feature: ['patterns', 'integration-points', 'testing', 'dependencies'] }
function selectAngles(taskDescription, count) { const text = taskDescription.toLowerCase() let preset = 'feature' if (/refactor|architect|restructure|modular/.test(text)) preset = 'architecture' else if (/security|auth|permission|access/.test(text)) preset = 'security' else if (/performance|slow|optimi|cache/.test(text)) preset = 'performance' else if (/fix|bug|error|issue|broken/.test(text)) preset = 'bugfix' return ANGLE_PRESETS[preset].slice(0, count) }
const selectedAngles = selectAngles(task_description, complexity === 'High' ? 4 : (complexity === 'Medium' ? 3 : 1))
// Direct Claude planning ONLY for: Low + no prior analysis + single angle const planningStrategy = ( complexity === 'Low' && !hasPriorAnalysis && selectedAngles.length <= 1 ) ? 'Direct Claude Planning' : 'cli-lite-planning-agent'
console.log(Exploration Plan: ${complexity} | ${selectedAngles.join(', ')} | ${planningStrategy})
Launch Parallel Explorations:
CRITICAL: MUST NOT use run_in_background: true — exploration results are REQUIRED before planning.
const explorationTasks = selectedAngles.map((angle, index) =>
Task(
subagent_type="cli-explore-agent",
run_in_background=false,
description=Explore: ${angle},
prompt=`
Task Objective
Execute ${angle} exploration for task planning context.
Output Location
Session Folder: ${sessionFolder} Output File: ${sessionFolder}/exploration-${angle}.json
Assigned Context
- Exploration Angle: ${angle}
- Task Description: ${task_description}
- Exploration Index: ${index + 1} of ${selectedAngles.length}
Exploration Strategy (${angle} focus)
Step 1: Structural Scan (Bash)
- get_modules_by_depth.sh → identify modules related to ${angle}
- find/rg → locate files relevant to ${angle} aspect
- Analyze imports/dependencies from ${angle} perspective
Step 2: Semantic Analysis (Gemini CLI)
- How does existing code handle ${angle} concerns?
- What patterns are used for ${angle}?
- Where would new code integrate from ${angle} viewpoint?
Step 3: Write Output
- Consolidate ${angle} findings into JSON
- Identify ${angle}-specific clarification needs
Expected Output
Schema: explore-json-schema.json (auto-loaded by agent)
- All fields scoped to ${angle} perspective
- Ensure rationale is specific and >10 chars (not generic)
- Include file:line locations in integration_points
- _metadata.exploration_angle: "${angle}"
Success Criteria
- get_modules_by_depth.sh executed
- At least 3 relevant files with specific rationale (>10 chars) + role classification
- Patterns are actionable (code examples, not generic advice)
- Integration points include file:line locations
- Constraints are project-specific to ${angle}
- JSON follows schema; clarification_needs includes options + recommended
- Files with relevance >= 0.7 have key_code array + topic_relation
Execution
Write: `${sessionFolder}/exploration-${angle}.json` Return: 2-3 sentence summary of ${angle} findings ` ) ) // Execute all exploration tasks in parallel
Auto-discover & Build Manifest:
const explorationFiles = bash(find ${sessionFolder} -name "exploration-*.json" -type f)
.split('\n').filter(f => f.trim())
const explorationManifest = { session_id: sessionId, task_description: task_description, timestamp: getUtc8ISOString(), complexity: complexity, exploration_count: explorationFiles.length, explorations: explorationFiles.map(file => { const data = JSON.parse(Read(file)) return { angle: data._metadata.exploration_angle, file: path.basename(file), path: file, index: data._metadata.exploration_index } }) }
Write(${sessionFolder}/explorations-manifest.json, JSON.stringify(explorationManifest, null, 2))
console.log(Exploration complete: ${explorationManifest.explorations.map(e => e.angle).join(', ')})
// TodoWrite: Phase 1 → completed, Phase 2 → in_progress
Output: exploration-{angle}.json (1-4 files) + explorations-manifest.json
LP-Phase 2: Clarification (Optional, Multi-Round)
Skip if: No exploration or clarification_needs is empty across all explorations
CRITICAL: AskUserQuestion limits max 4 questions per call. MUST execute multiple rounds to exhaust all clarification needs.
const manifest = file_exists(${sessionFolder}/explorations-manifest.json)
? JSON.parse(Read(${sessionFolder}/explorations-manifest.json))
: { exploration_count: 0, explorations: [] }
const explorations = manifest.explorations.map(exp => ({
angle: exp.angle,
data: JSON.parse(Read(exp.path))
}))
// Aggregate from all explorations const allClarifications = [] explorations.forEach(exp => { if (exp.data.clarification_needs?.length > 0) { exp.data.clarification_needs.forEach(need => { allClarifications.push({ ...need, source_angle: exp.angle }) }) } })
// Intelligent dedup: merge similar intent across angles, combine options const dedupedClarifications = intelligentMerge(allClarifications)
if (workflowPreferences.autoYes) {
console.log([Auto] Skipping ${dedupedClarifications.length} clarification questions)
} else if (dedupedClarifications.length > 0) {
const BATCH_SIZE = 4
const totalRounds = Math.ceil(dedupedClarifications.length / BATCH_SIZE)
for (let i = 0; i < dedupedClarifications.length; i += BATCH_SIZE) {
const batch = dedupedClarifications.slice(i, i + BATCH_SIZE)
const currentRound = Math.floor(i / BATCH_SIZE) + 1
console.log(### Clarification Round ${currentRound}/${totalRounds})
AskUserQuestion({
questions: batch.map(need => ({
question: `[${need.source_angle}] ${need.question}\n\nContext: ${need.context}`,
header: need.source_angle.substring(0, 12),
multiSelect: false,
options: need.options.map((opt, index) => ({
label: need.recommended === index ? `${opt} ★` : opt,
description: need.recommended === index ? `Recommended` : `Use ${opt}`
}))
}))
})
// Store batch responses in clarificationContext before next round
} }
Output: clarificationContext (in-memory)
LP-Phase 3: Planning
IMPORTANT: LP-Phase 3 is planning only — NO code execution. All execution happens in LP-Phase 5 via lite-execute.
Executor Assignment (after plan generation):
// Priority: 1. User explicit ("用 gemini 分析..." → gemini) | 2. Default → agent
const executorAssignments = {} // { taskId: { executor: 'gemini'|'codex'|'agent', reason } }
const taskFiles = Glob(${sessionFolder}/.task/TASK-*.json)
taskFiles.forEach(taskPath => {
const task = JSON.parse(Read(taskPath))
executorAssignments[task.id] = { executor: '...', reason: '...' }
})
Low Complexity — Direct planning by Claude:
const schema = Bash(cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json)
const manifest = file_exists(${sessionFolder}/explorations-manifest.json)
? JSON.parse(Read(${sessionFolder}/explorations-manifest.json))
: { explorations: [] }
manifest.explorations.forEach(exp => {
console.log(\n### Exploration: ${exp.angle}\n${Read(exp.path)})
})
// Generate tasks — MUST incorporate exploration insights // Field names: convergence.criteria (not acceptance), files[].change (not modification_points), test (not verification) const tasks = [ { id: "TASK-001", title: "...", description: "...", depends_on: [], convergence: { criteria: ["..."] }, files: [{ path: "...", change: "..." }], implementation: ["..."], test: "..." } ]
const taskDir = ${sessionFolder}/.task
Bash(mkdir -p "${taskDir}")
tasks.forEach(task => Write(${taskDir}/${task.id}.json, JSON.stringify(task, null, 2)))
const plan = {
summary: "...", approach: "...",
task_ids: tasks.map(t => t.id), task_count: tasks.length,
complexity: "Low", estimated_time: "...", recommended_execution: "Agent",
_metadata: { timestamp: getUtc8ISOString(), source: "direct-planning", planning_mode: "direct", plan_type: "feature" }
}
Write(${sessionFolder}/plan.json, JSON.stringify(plan, null, 2))
// MUST continue to LP-Phase 4 — DO NOT execute code here
Medium/High Complexity — Invoke cli-lite-planning-agent:
Task( subagent_type="cli-lite-planning-agent", run_in_background=false, description="Generate detailed implementation plan", prompt=` Generate implementation plan and write plan.json.
Output Location
Session Folder: ${sessionFolder} Output Files:
- ${sessionFolder}/planning-context.md (evidence + understanding)
- ${sessionFolder}/plan.json (plan overview — NO embedded tasks[])
- ${sessionFolder}/.task/TASK-*.json (independent task files, one per task)
Schema Reference
Execute: cat ~/.ccw/workflows/cli-templates/schemas/plan-overview-base-schema.json
Project Context (MANDATORY)
Execute: ccw spec load --category planning CRITICAL: All generated tasks MUST comply with constraints in specs/*.md
Task Description
${task_description}
Multi-Angle Exploration Context
${manifest.explorations.length > 0
? manifest.explorations.map(exp => ### Exploration: ${exp.angle} (${exp.file}) Path: ${exp.path} Read this file for detailed ${exp.angle} analysis.).join('\n\n') + `
Total: ${manifest.exploration_count} | Angles: ${manifest.explorations.map(e => e.angle).join(', ')}
Manifest: ${sessionFolder}/explorations-manifest.json :No exploration files. Task Description contains "## Prior Analysis" — use as primary planning context.`}
User Clarifications
${JSON.stringify(clarificationContext) || "None"}
Complexity Level
${complexity}
Requirements
- _metadata.exploration_angles: ${JSON.stringify(manifest.explorations.map(e => e.angle))}
- Two-layer output: plan.json (task_ids[], NO tasks[]) + .task/TASK-*.json
- Follow plan-overview-base-schema.json for plan.json, task-schema.json for .task/*.json
- Field names: files[].change (not modification_points), convergence.criteria (not acceptance)
Task Grouping Rules
- Group by feature: All changes for one feature = one task (even if 3-5 files)
- Group by context: Related functional changes can be grouped together
- Minimize agent count: Group simple unrelated tasks to reduce overhead
- Avoid file-per-task: Do NOT create separate tasks for each file
- Substantial tasks: Each task = 15-60 minutes of work
- True dependencies only: depends_on only when Task B needs Task A's output
- Prefer parallel: Most tasks should be independent
Execution
- Read schema → 2. ccw spec load → 3. Read ALL exploration files → 4. Synthesize + generate
- Write: planning-context.md, .task/TASK-*.json, plan.json (task_ids[], NO tasks[])
- Return brief completion summary ` )
Output: ${sessionFolder}/plan.json
// TodoWrite: Phase 3 → completed, Phase 4 → in_progress
LP-Phase 4: Task Confirmation & Execution Selection
Display Plan:
const plan = JSON.parse(Read(${sessionFolder}/plan.json))
const tasks = (plan.task_ids || []).map(id => JSON.parse(Read(${sessionFolder}/.task/${id}.json)))
console.log(`
Implementation Plan
Summary: ${plan.summary}
Approach: ${plan.approach}
Tasks (${tasks.length}):
${tasks.map((t, i) => ${i+1}. ${t.title} (${t.scope || t.files?.[0]?.path || ''})).join('\n')}
Complexity: ${plan.complexity} | Time: ${plan.estimated_time} | Recommended: ${plan.recommended_execution}
`)
Collect Confirmation:
let userSelection
if (workflowPreferences.autoYes) {
console.log([Auto] Allow & Execute | Auto | Skip)
userSelection = { confirmation: "Allow", execution_method: "Auto", code_review_tool: "Skip" }
} else {
// "Other" in Execution allows specifying CLI tools from ~/.claude/cli-tools.json
userSelection = AskUserQuestion({
questions: [
{
question: Confirm plan and authorize execution? (${tasks.length} tasks, ${plan.complexity}),
header: "Confirm",
multiSelect: false,
options: [
{ label: "Allow & Execute", description: "Approve plan and begin execution immediately (no further prompts)" },
{ label: "Modify", description: "Adjust before execution" },
{ label: "Cancel", description: "Abort workflow" }
]
},
{
question: "Execution method:",
header: "Execution",
multiSelect: false,
options: [
{ label: "Agent", description: "@code-developer agent" },
{ label: "Codex", description: "codex CLI tool" },
{ label: "Auto", description: Auto: ${plan.complexity === 'Low' ? 'Agent' : 'Codex'} }
]
},
{
question: "Code review after execution?",
header: "Review",
multiSelect: false,
options: [
{ label: "Gemini Review", description: "Gemini CLI review" },
{ label: "Codex Review", description: "Git-aware review (prompt OR --uncommitted)" },
{ label: "Agent Review", description: "@code-reviewer agent" },
{ label: "Skip", description: "No review" }
]
}
]
})
}
// TodoWrite: Phase 4 → completed [${userSelection.execution_method} + ${userSelection.code_review_tool}] , Phase 5 → in_progress
LP-Phase 5: Handoff to Execution
CRITICAL: lite-plan NEVER executes code directly. ALL execution goes through lite-execute.
Build executionContext:
const manifest = file_exists(${sessionFolder}/explorations-manifest.json)
? JSON.parse(Read(${sessionFolder}/explorations-manifest.json))
: { exploration_count: 0, explorations: [] }
const explorations = {}
manifest.explorations.forEach(exp => {
if (file_exists(exp.path)) explorations[exp.angle] = JSON.parse(Read(exp.path))
})
const plan = JSON.parse(Read(${sessionFolder}/plan.json))
executionContext = {
planObject: plan,
taskFiles: (plan.task_ids || []).map(id => ({ id, path: ${sessionFolder}/.task/${id}.json })),
explorationsContext: explorations,
explorationAngles: manifest.explorations.map(e => e.angle),
explorationManifest: manifest,
clarificationContext: clarificationContext || null,
executionMethod: userSelection.execution_method,
codeReviewTool: userSelection.code_review_tool,
originalUserInput: task_description,
executorAssignments: executorAssignments, // { taskId: { executor, reason } } — overrides executionMethod
session: {
id: sessionId,
folder: sessionFolder,
artifacts: {
explorations: manifest.explorations.map(exp => ({ angle: exp.angle, path: exp.path })),
explorations_manifest: ${sessionFolder}/explorations-manifest.json,
plan: ${sessionFolder}/plan.json,
task_dir: ${sessionFolder}/.task
}
}
}
Handoff:
if (!workflowPreferences.autoYes) {
console.log(Handing off to execution engine. No further prompts.)
}
// TodoWrite: Phase 5 → completed, add LE-Phase 1 → in_progress
const taskCount = (plan.task_ids || []).length
TodoWrite({ todos: [
{ content: "LP-Phase 1: Exploration", status: "completed" },
{ content: "LP-Phase 2: Clarification", status: "completed" },
{ content: "LP-Phase 3: Planning", status: "completed" },
{ content: LP-Phase 4: Confirmed [${userSelection.execution_method}], status: "completed" },
{ content: LP-Phase 5: Handoff → lite-execute, status: "completed" },
{ content: LE-Phase 1: Task Loading [${taskCount} tasks], status: "in_progress", activeForm: "Loading tasks" }
]})
Skill("lite-execute") // executionContext passed as global variable (Mode 1: In-Memory Plan)
Session Folder Structure
.workflow/.lite-plan/{task-slug}-{YYYY-MM-DD}/ ├── exploration-{angle}.json (1-4) # Per-angle exploration ├── explorations-manifest.json # Exploration index ├── planning-context.md # Evidence paths + understanding ├── plan.json # Plan overview (task_ids[]) └── .task/ ├── TASK-001.json ├── TASK-002.json └── ...
Error Handling
Error Resolution
Exploration agent failure Skip exploration, continue with task description only
Planning agent failure Fallback to direct planning by Claude
Clarification timeout Use exploration findings as-is
Confirmation timeout Save context, display resume instructions
Modify loop > 3 times Suggest breaking task or using /workflow-plan