Work Unit 005: In-Place Project Initialization for Web VMs
Behavioral Goal
As a web VM user opening a repository in Claude Code web
I need the ability to create sow projects on the current branch without worktrees or Claude Code launching
So that I can use sow's structured orchestration workflow in ephemeral web environments where the traditional local initialization flow doesn't apply.
Success Criteria (What Reviewers Will Verify):
- Users can run
sow project init --type standard --name "feature-name" --desc "Description" to create a project on the current branch
- The command creates
.sow/project/ in-place without attempting worktree creation
- The command does not attempt to launch Claude Code (which is already running in web VMs)
- The existing
sow project interactive wizard continues to work unchanged for local users
- Both initialization paths share common logic (no code duplication)
- All project types (standard, design, breakdown, exploration) are supported
- Environment detection via
CLAUDE_CODE_REMOTE=true works correctly
Existing Code Context
Explanatory Context
This work unit builds upon the existing interactive project wizard (sow project) which currently handles project creation for local CLI users. The wizard creates worktrees for branch isolation and launches Claude Code with a project-specific prompt. This flow works perfectly for local development but doesn't fit web VMs where:
- The repository is already cloned on the target branch (no worktree needed)
- Claude Code is already running (can't be launched)
- User interaction happens through the web UI, not CLI flags
We need to extract the core initialization logic from the wizard and create a programmatic command (sow project init) that performs in-place initialization using flags instead of interactive prompts. The wizard uses the Project SDK's state.Create() function to initialize project state, writes context files (like GitHub issue data), and generates multi-layer prompts. We'll reuse these patterns but adapt them for programmatic, in-place execution.
The project SDK provides a robust builder pattern for creating projects, with state machine integration and phase-specific initialization. The initializeProject() helper in shared.go demonstrates the initialization flow: create directories, write context files, call state.Create(), and handle artifacts. We'll reuse this function with conditional worktree logic.
Smart prompt selection is handled by a SessionStart hook script (embedded in work unit 003) that checks for .sow/project/ existence and loads either the project-specific orchestrator prompt or a general mode operator prompt. This enables seamless mode switching in web VMs.
Reference List
Key Files:
cli/cmd/project/wizard_state.go:59-132 - initializeProject() function (core initialization logic to reuse)
cli/cmd/project/shared.go:20-132 - Shared helpers for project creation (context handling, prompt generation)
cli/cmd/project/project.go:8-38 - Main project command structure (where init subcommand will be registered)
cli/internal/sdks/project/builder.go:29-331 - ProjectTypeConfigBuilder (state machine and phase setup)
cli/internal/sdks/project/state/project.go - state.Create() function (SDK for state initialization)
cli/internal/prompts/prompts.go:20-32 - Embedded prompt templates (example of embed.FS pattern)
Related Patterns:
cli/cmd/project/wizard_state.go:840-925 - finalizeCreation() method (worktree creation, initialization, Claude launch)
cli/cmd/project/shared.go:151-185 - generateNewProjectPrompt() (3-layer prompt structure)
cli/internal/sdks/project/state/loader.go - State loading and persistence
cli/cmd/init.go - Repository initialization patterns
Existing Documentation Context
Design Document (Section 5: Project Initialization) - The design doc describes the fundamental difference between local and web VM workflows. Local users run sow project new which creates worktrees and launches Claude Code. Web VM users need sow project init for in-place initialization since the branch is already cloned and Claude is already running. The design emphasizes that these are complementary paths, not replacements, and should share common initialization logic.
Discovery Document (Lines 335-422) - The discovery analysis found that 60% of the project initialization infrastructure already exists. The wizard demonstrates all the patterns we need (SDK usage, context management, prompt generation), but it's tightly coupled to the interactive TUI and worktree flow. The analysis recommends extracting shared logic to shared.go and adding environment detection for conditional worktree creation.
Task Description - This task explicitly scopes both the new sow project init command AND the smart prompt selector script (embedded in CLI). The prompt selector checks .sow/project/ existence and loads the appropriate prompt (project-specific orchestrator or general mode operator). The general mode prompt (also embedded) guides users toward creating projects when appropriate, completing the operator-to-orchestrator transition.
Implementation Approach
Core Components
1. New Command: sow project init (create cli/cmd/project/init.go)
A new Cobra command that accepts all project parameters via flags:
sow project init \
--type standard \
--name "implement-jwt-auth" \
--desc "Add JWT authentication to API" \
[--issue N]
The command should:
- Parse and validate all required flags (type, name, desc)
- Normalize the project name into a branch name using existing patterns
- Detect the current environment (local vs web VM via
CLAUDE_CODE_REMOTE)
- Call shared initialization logic (no worktree creation in web mode)
- Create
.sow/project/ on the current branch
- Generate appropriate success messages (no Claude launch in web mode)
2. Shared Initialization Logic (refactor cli/cmd/project/shared.go)
Extract common initialization from wizard's finalizeCreation() into reusable functions:
createProjectInPlace(ctx, branch, name, type, issue, knowledgeFiles) - Initialization without worktree
isWebVM() - Detect CLAUDE_CODE_REMOTE=true environment
- Existing
initializeProject() already handles core logic (directory creation, state.Create(), artifact registration)
The wizard should use these shared functions with conditional branching:
- Web VM mode: In-place initialization, no worktree, no Claude launch
- Local mode: Worktree creation, initialization in worktree, Claude launch
3. General Mode Operator Prompt (embedded at cli/internal/claude/prompts/general.md)
Template content for operator mode (when no .sow/project/ exists):
You are operating in general mode. No active project exists.
User's prompt: "{USER_PROMPT}"
Analyze whether this task would benefit from structured orchestration:
- Feature implementation → `sow project init --type standard`
- Design/architecture → `sow project init --type design`
- Research/exploration → `sow project init --type exploration`
- Complex breakdown → `sow project init --type breakdown`
If structured orchestration would help, ask the user if they want to create a project.
If yes, run the appropriate `sow project init` command.
If the user prefers ad-hoc work, proceed as a helpful coding assistant.
This prompt enables Claude to recognize when to suggest project creation and explain the mode transition.
4. Smart Prompt Selector (embedded at cli/internal/claude/scripts/session-start-prompt.sh)
Shell script that determines which prompt to load:
#!/bin/bash
# Smart prompt selector for Claude Code SessionStart hook
if [ -d ".sow/project" ]; then
# Project exists - load project-specific orchestrator prompt
TYPE=$(grep "^type:" .sow/project/state.yaml | cut -d: -f2 | tr -d ' ')
sow prompt project/$TYPE
else
# No project - load general mode operator prompt
sow prompt general
fi
This script is called by the SessionStart hook and provides context-aware prompts.
Environment Detection
Detect web VM environment using the CLAUDE_CODE_REMOTE environment variable:
func isWebVM() bool {
return os.Getenv("CLAUDE_CODE_REMOTE") == "true"
}
Use this detection to conditionally skip:
- Worktree creation (web VMs work on cloned branch directly)
- Claude Code launching (already running in web VMs)
- Uncommitted changes checks (not needed for in-place init)
Integration Points
Wizard Modifications (minimal changes to wizard_state.go):
finalizeCreation() should call shared initialization functions
- Add environment detection:
if isWebVM() { /* in-place path */ } else { /* worktree path */ }
- Keep all interactive flows unchanged (user-facing behavior identical)
Prompt Command Enhancement (minimal changes to cli/cmd/prompt.go):
- Add support for
sow prompt general to render general mode prompt
- Add support for
sow prompt project/{type} to render project-specific prompts
Project SDK (no changes needed):
state.Create() already supports in-place initialization
- Builder pattern already handles all project types
- Artifact registration already works with relative paths
Dependencies
None - This work unit is independent and can be implemented in parallel with other work units. It does not depend on:
- Work unit 003 (Agent Embedding) - though it will embed the prompts/scripts created here
- Work unit 004 (GitHub API) - project init works without GitHub integration
- Work unit 006 (Installation) - init command is independent of installation mechanism
Acceptance Criteria
Behavioral outcomes that reviewers will verify:
- In-place initialization works: Running
sow project init --type standard --name "test" --desc "Test project" creates .sow/project/state.yaml on the current branch without creating a worktree
- Environment detection works: Setting
CLAUDE_CODE_REMOTE=true causes the wizard to skip worktree creation and Claude launching
- All project types supported: The init command accepts --type values: standard, design, breakdown, exploration
- Issue linking works: The
--issue N flag correctly fetches issue data and writes context files (when GitHub client is available)
- Wizard preserved: The existing
sow project interactive wizard continues to work with identical user experience for local users
- Smart prompt selection works: The session-start-prompt.sh script correctly detects
.sow/project/ and loads appropriate prompts
- General mode prompt exists:
sow prompt general renders the operator mode prompt
- No code duplication: Wizard and init command share common initialization logic via functions in
shared.go
Testing Strategy
Unit Tests
Command parsing tests (cli/cmd/project/init_test.go):
- Flag validation (required vs optional)
- Branch name normalization (matches wizard behavior)
- Error handling for invalid project types
Shared logic tests (cli/cmd/project/shared_test.go):
createProjectInPlace() creates correct directory structure
isWebVM() correctly detects environment variable
- Shared functions match wizard behavior
Environment detection tests:
- Test with
CLAUDE_CODE_REMOTE=true (web VM mode)
- Test with
CLAUDE_CODE_REMOTE unset (local mode)
- Test with
CLAUDE_CODE_REMOTE=false (explicit local mode)
Integration Tests
End-to-end init command (cli/cmd/project/init_integration_test.go):
- Create project on current branch
- Verify
.sow/project/state.yaml exists and is valid
- Verify no worktree created
- Verify no Claude Code launch attempted
Wizard backward compatibility (cli/cmd/project/wizard_integration_test.go):
- Existing wizard tests pass unchanged
- Wizard still creates worktrees in local mode
- Wizard still launches Claude Code in local mode
Smart prompt selector (manual/script tests):
- Script correctly detects project existence
- Script loads project-specific prompt when project exists
- Script loads general mode prompt when no project exists
Manual Verification Checklist
Implementation Notes
General Mode Prompt Behavior
The general mode prompt enables flexible operation:
- User can work on ad-hoc tasks without creating a project
- Claude suggests project creation when structured work is detected
- User controls when to transition to orchestrator mode
- Mode automatically switches when
.sow/project/ is created
SessionStart Prompt Selector Behavior
The smart selector runs on every session start:
- Checks
.sow/project/ directory existence
- If exists: Parses
type: from state.yaml, loads sow prompt project/{type}
- If not exists: Loads
sow prompt general
- Provides context-aware greeting with appropriate guidance
Worktree Conditional Logic
Environment detection determines initialization path:
Shared Initialization Logic
Both paths use the same core functions:
initializeProject() - Creates directories, state, artifacts
generateNewProjectPrompt() - Builds 3-layer prompt structure
determineKnowledgeInputPhase() - Maps files to phases
- SDK's
state.Create() - Initializes state machine
This ensures consistent behavior regardless of initialization path.
Flag Naming Conventions
Follow existing sow CLI patterns:
--type matches wizard terminology (standard, design, breakdown, exploration)
--name matches wizard's "project name" concept
--desc provides short description (like wizard's prompt entry)
--issue matches existing GitHub issue integration
Error Handling
The command should fail gracefully with helpful messages:
- Invalid project type → "Unknown project type. Valid types: standard, design, breakdown, exploration"
- Project already exists → "Project already exists on branch. Use 'sow project delete' to remove."
- Invalid branch name → "Invalid branch name characters. Use alphanumeric and hyphens only."
- Missing GitHub CLI (with --issue) → "GitHub CLI required for issue linking. Install gh or omit --issue flag."
Future Enhancement Opportunities
This work unit establishes patterns for future improvements:
- Knowledge file selection via
--knowledge flag
- Custom branch name via
--branch flag
- Batch project creation via configuration file
- Project templates with predefined artifacts
These are explicitly out of scope for this work unit but can be added later using the foundation created here.
Files to Create
New Files:
cli/cmd/project/init.go - sow project init command implementation
cli/internal/claude/prompts/general.md - General mode operator prompt template
cli/internal/claude/scripts/session-start-prompt.sh - Smart prompt selector script
Modified Files:
cli/cmd/project/shared.go - Add createProjectInPlace(), isWebVM() helper functions
cli/cmd/project/wizard_state.go - Refactor finalizeCreation() to use shared logic with environment detection
cli/cmd/project/project.go - Register init subcommand
cli/cmd/prompt.go - Add support for general and project/{type} prompt rendering (if not already present)
Test Files:
cli/cmd/project/init_test.go - Unit tests for init command
cli/cmd/project/init_integration_test.go - Integration tests for init command
- Updates to
cli/cmd/project/shared_test.go - Tests for new shared functions
- Updates to
cli/cmd/project/wizard_integration_test.go - Environment detection tests
Artifact Registration
Once the specification is complete, register it:
sow task output add --id 005 --type work_unit_spec --path .sow/project/work-units/005-project-init.md
sow task set --id 005 metadata.artifact_path .sow/project/work-units/005-project-init.md
sow task set --id 005 status needs_review
Specification Version: 1.0
Author: Decomposer Agent
Date: 2025-11-08
Estimated Implementation Effort: 2-3 days
Work Unit 005: In-Place Project Initialization for Web VMs
Behavioral Goal
As a web VM user opening a repository in Claude Code web
I need the ability to create sow projects on the current branch without worktrees or Claude Code launching
So that I can use sow's structured orchestration workflow in ephemeral web environments where the traditional local initialization flow doesn't apply.
Success Criteria (What Reviewers Will Verify):
sow project init --type standard --name "feature-name" --desc "Description"to create a project on the current branch.sow/project/in-place without attempting worktree creationsow projectinteractive wizard continues to work unchanged for local usersCLAUDE_CODE_REMOTE=trueworks correctlyExisting Code Context
Explanatory Context
This work unit builds upon the existing interactive project wizard (
sow project) which currently handles project creation for local CLI users. The wizard creates worktrees for branch isolation and launches Claude Code with a project-specific prompt. This flow works perfectly for local development but doesn't fit web VMs where:We need to extract the core initialization logic from the wizard and create a programmatic command (
sow project init) that performs in-place initialization using flags instead of interactive prompts. The wizard uses the Project SDK'sstate.Create()function to initialize project state, writes context files (like GitHub issue data), and generates multi-layer prompts. We'll reuse these patterns but adapt them for programmatic, in-place execution.The project SDK provides a robust builder pattern for creating projects, with state machine integration and phase-specific initialization. The
initializeProject()helper inshared.godemonstrates the initialization flow: create directories, write context files, callstate.Create(), and handle artifacts. We'll reuse this function with conditional worktree logic.Smart prompt selection is handled by a SessionStart hook script (embedded in work unit 003) that checks for
.sow/project/existence and loads either the project-specific orchestrator prompt or a general mode operator prompt. This enables seamless mode switching in web VMs.Reference List
Key Files:
cli/cmd/project/wizard_state.go:59-132-initializeProject()function (core initialization logic to reuse)cli/cmd/project/shared.go:20-132- Shared helpers for project creation (context handling, prompt generation)cli/cmd/project/project.go:8-38- Main project command structure (where init subcommand will be registered)cli/internal/sdks/project/builder.go:29-331- ProjectTypeConfigBuilder (state machine and phase setup)cli/internal/sdks/project/state/project.go-state.Create()function (SDK for state initialization)cli/internal/prompts/prompts.go:20-32- Embedded prompt templates (example of embed.FS pattern)Related Patterns:
cli/cmd/project/wizard_state.go:840-925-finalizeCreation()method (worktree creation, initialization, Claude launch)cli/cmd/project/shared.go:151-185-generateNewProjectPrompt()(3-layer prompt structure)cli/internal/sdks/project/state/loader.go- State loading and persistencecli/cmd/init.go- Repository initialization patternsExisting Documentation Context
Design Document (Section 5: Project Initialization) - The design doc describes the fundamental difference between local and web VM workflows. Local users run
sow project newwhich creates worktrees and launches Claude Code. Web VM users needsow project initfor in-place initialization since the branch is already cloned and Claude is already running. The design emphasizes that these are complementary paths, not replacements, and should share common initialization logic.Discovery Document (Lines 335-422) - The discovery analysis found that 60% of the project initialization infrastructure already exists. The wizard demonstrates all the patterns we need (SDK usage, context management, prompt generation), but it's tightly coupled to the interactive TUI and worktree flow. The analysis recommends extracting shared logic to
shared.goand adding environment detection for conditional worktree creation.Task Description - This task explicitly scopes both the new
sow project initcommand AND the smart prompt selector script (embedded in CLI). The prompt selector checks.sow/project/existence and loads the appropriate prompt (project-specific orchestrator or general mode operator). The general mode prompt (also embedded) guides users toward creating projects when appropriate, completing the operator-to-orchestrator transition.Implementation Approach
Core Components
1. New Command:
sow project init(createcli/cmd/project/init.go)A new Cobra command that accepts all project parameters via flags:
The command should:
CLAUDE_CODE_REMOTE).sow/project/on the current branch2. Shared Initialization Logic (refactor
cli/cmd/project/shared.go)Extract common initialization from wizard's
finalizeCreation()into reusable functions:createProjectInPlace(ctx, branch, name, type, issue, knowledgeFiles)- Initialization without worktreeisWebVM()- DetectCLAUDE_CODE_REMOTE=trueenvironmentinitializeProject()already handles core logic (directory creation, state.Create(), artifact registration)The wizard should use these shared functions with conditional branching:
3. General Mode Operator Prompt (embedded at
cli/internal/claude/prompts/general.md)Template content for operator mode (when no
.sow/project/exists):You are operating in general mode. No active project exists. User's prompt: "{USER_PROMPT}" Analyze whether this task would benefit from structured orchestration: - Feature implementation → `sow project init --type standard` - Design/architecture → `sow project init --type design` - Research/exploration → `sow project init --type exploration` - Complex breakdown → `sow project init --type breakdown` If structured orchestration would help, ask the user if they want to create a project. If yes, run the appropriate `sow project init` command. If the user prefers ad-hoc work, proceed as a helpful coding assistant.This prompt enables Claude to recognize when to suggest project creation and explain the mode transition.
4. Smart Prompt Selector (embedded at
cli/internal/claude/scripts/session-start-prompt.sh)Shell script that determines which prompt to load:
This script is called by the SessionStart hook and provides context-aware prompts.
Environment Detection
Detect web VM environment using the
CLAUDE_CODE_REMOTEenvironment variable:Use this detection to conditionally skip:
Integration Points
Wizard Modifications (minimal changes to
wizard_state.go):finalizeCreation()should call shared initialization functionsif isWebVM() { /* in-place path */ } else { /* worktree path */ }Prompt Command Enhancement (minimal changes to
cli/cmd/prompt.go):sow prompt generalto render general mode promptsow prompt project/{type}to render project-specific promptsProject SDK (no changes needed):
state.Create()already supports in-place initializationDependencies
None - This work unit is independent and can be implemented in parallel with other work units. It does not depend on:
Acceptance Criteria
Behavioral outcomes that reviewers will verify:
sow project init --type standard --name "test" --desc "Test project"creates.sow/project/state.yamlon the current branch without creating a worktreeCLAUDE_CODE_REMOTE=truecauses the wizard to skip worktree creation and Claude launching--issue Nflag correctly fetches issue data and writes context files (when GitHub client is available)sow projectinteractive wizard continues to work with identical user experience for local users.sow/project/and loads appropriate promptssow prompt generalrenders the operator mode promptshared.goTesting Strategy
Unit Tests
Command parsing tests (
cli/cmd/project/init_test.go):Shared logic tests (
cli/cmd/project/shared_test.go):createProjectInPlace()creates correct directory structureisWebVM()correctly detects environment variableEnvironment detection tests:
CLAUDE_CODE_REMOTE=true(web VM mode)CLAUDE_CODE_REMOTEunset (local mode)CLAUDE_CODE_REMOTE=false(explicit local mode)Integration Tests
End-to-end init command (
cli/cmd/project/init_integration_test.go):.sow/project/state.yamlexists and is validWizard backward compatibility (
cli/cmd/project/wizard_integration_test.go):Smart prompt selector (manual/script tests):
Manual Verification Checklist
sow project initon clean branch - verify state createdsow project initwith all project types - verify each workssow project init --issue N- verify issue context writtenCLAUDE_CODE_REMOTE=true, run wizard - verify no worktree/launchImplementation Notes
General Mode Prompt Behavior
The general mode prompt enables flexible operation:
.sow/project/is createdSessionStart Prompt Selector Behavior
The smart selector runs on every session start:
.sow/project/directory existencetype:from state.yaml, loadssow prompt project/{type}sow prompt generalWorktree Conditional Logic
Environment detection determines initialization path:
CLAUDE_CODE_REMOTE=true: In-place mode (web VM).sow/project/on current branchCLAUDE_CODE_REMOTEunset or false: Worktree mode (local)Shared Initialization Logic
Both paths use the same core functions:
initializeProject()- Creates directories, state, artifactsgenerateNewProjectPrompt()- Builds 3-layer prompt structuredetermineKnowledgeInputPhase()- Maps files to phasesstate.Create()- Initializes state machineThis ensures consistent behavior regardless of initialization path.
Flag Naming Conventions
Follow existing sow CLI patterns:
--typematches wizard terminology (standard, design, breakdown, exploration)--namematches wizard's "project name" concept--descprovides short description (like wizard's prompt entry)--issuematches existing GitHub issue integrationError Handling
The command should fail gracefully with helpful messages:
Future Enhancement Opportunities
This work unit establishes patterns for future improvements:
--knowledgeflag--branchflagThese are explicitly out of scope for this work unit but can be added later using the foundation created here.
Files to Create
New Files:
cli/cmd/project/init.go-sow project initcommand implementationcli/internal/claude/prompts/general.md- General mode operator prompt templatecli/internal/claude/scripts/session-start-prompt.sh- Smart prompt selector scriptModified Files:
cli/cmd/project/shared.go- AddcreateProjectInPlace(),isWebVM()helper functionscli/cmd/project/wizard_state.go- RefactorfinalizeCreation()to use shared logic with environment detectioncli/cmd/project/project.go- Register init subcommandcli/cmd/prompt.go- Add support forgeneralandproject/{type}prompt rendering (if not already present)Test Files:
cli/cmd/project/init_test.go- Unit tests for init commandcli/cmd/project/init_integration_test.go- Integration tests for init commandcli/cmd/project/shared_test.go- Tests for new shared functionscli/cmd/project/wizard_integration_test.go- Environment detection testsArtifact Registration
Once the specification is complete, register it:
Specification Version: 1.0
Author: Decomposer Agent
Date: 2025-11-08
Estimated Implementation Effort: 2-3 days