Skip to content

In-Place Project Initialization for Web VMs #92

Description

@jmgilman

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):

  1. Users can run sow project init --type standard --name "feature-name" --desc "Description" to create a project on the current branch
  2. The command creates .sow/project/ in-place without attempting worktree creation
  3. The command does not attempt to launch Claude Code (which is already running in web VMs)
  4. The existing sow project interactive wizard continues to work unchanged for local users
  5. Both initialization paths share common logic (no code duplication)
  6. All project types (standard, design, breakdown, exploration) are supported
  7. 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:

  1. 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
  2. Environment detection works: Setting CLAUDE_CODE_REMOTE=true causes the wizard to skip worktree creation and Claude launching
  3. All project types supported: The init command accepts --type values: standard, design, breakdown, exploration
  4. Issue linking works: The --issue N flag correctly fetches issue data and writes context files (when GitHub client is available)
  5. Wizard preserved: The existing sow project interactive wizard continues to work with identical user experience for local users
  6. Smart prompt selection works: The session-start-prompt.sh script correctly detects .sow/project/ and loads appropriate prompts
  7. General mode prompt exists: sow prompt general renders the operator mode prompt
  8. 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

  • Run sow project init on clean branch - verify state created
  • Run sow project init with all project types - verify each works
  • Run sow project init --issue N - verify issue context written
  • Set CLAUDE_CODE_REMOTE=true, run wizard - verify no worktree/launch
  • Run wizard without env var - verify worktree/launch still work
  • Verify smart prompt selector script switches prompts correctly

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:

  • CLAUDE_CODE_REMOTE=true: In-place mode (web VM)

    • No worktree creation
    • No Claude Code launch
    • No uncommitted changes check
    • Creates .sow/project/ on current branch
  • CLAUDE_CODE_REMOTE unset or false: Worktree mode (local)

    • Creates worktree for branch isolation
    • Initializes project in worktree
    • Launches Claude Code with prompt
    • Checks for uncommitted changes

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    sowIssues managed by sow breakdown workflow

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions