-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Work Unit 006: Automated Installation & SessionStart Integration
Behavioral Goal
As a user opening a sow-enabled repository in Claude Code web, I need the sow CLI to be automatically installed and configured without manual intervention so that I can immediately start working with sow projects and agents in the ephemeral VM environment.
Success Criteria:
- User clones repository in Claude Code web
- SessionStart hook executes automatically on VM startup
- Script detects web VM environment and installs sow binary
sowcommand is available in PATH without user action.claude/directory is initialized with agents and commands- Smart prompt selector loads appropriate context-aware prompt
- Installation is idempotent (safe to run multiple times)
- Local development environments are unaffected (script exits early)
Existing Code Context
This work unit builds automation around the sow CLI binary distribution and Claude Code's SessionStart hook system to enable zero-setup web VM experiences.
Release Infrastructure
The sow project already has a complete release pipeline via GoReleaser that produces platform-specific binary archives. The installation script will leverage this existing infrastructure:
GoReleaser Configuration (.goreleaser.yml):
- Builds for Linux (amd64, arm64), macOS (amd64, arm64), Windows
- Archives named:
sow_{version}_{OS}_{arch}.tar.gz - Example:
sow_0.1.0_Linux_x86_64.tar.gz - Published to GitHub releases at
github.com/jmgilman/sow/releases - Archives contain:
sowbinary,LICENSE,README.md
Target Platforms:
- Primary: Linux x86_64 (Claude Code web VMs run on Linux)
- Secondary: macOS arm64, macOS x86_64 (for local testing)
- No Windows support needed (web VMs are Linux-only)
Embedding Pattern
The repository already uses Go's embed.FS pattern extensively for bundling templates and schemas into the CLI binary. The installation script and SessionStart hook configuration will follow this same pattern:
Existing Pattern (cli/internal/prompts/prompts.go):
//go:embed templates
var FS embed.FS
// Usage in code:
templates.Render(prompts.FS, "templates/guidance/research.md", data)This work unit will create a similar embedding structure at cli/internal/claude/ to bundle:
- Shell scripts (install-sow.sh, session-start-prompt.sh)
- Hook configuration (settings.json)
- Agent and command definitions (from work unit 003)
Environment Detection Variables
Claude Code web provides specific environment variables that enable detection and configuration:
CLAUDE_CODE_REMOTE: Set to "true" in web VMs, unset locally
- Used for: Detecting whether to run installation
- Pattern:
if [ "$CLAUDE_CODE_REMOTE" = "true" ]; then ...
CLAUDE_ENV_FILE: Path to persistent environment file (e.g., ~/.claude_env)
- Used for: Persisting PATH additions across sessions
- Pattern:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$CLAUDE_ENV_FILE"
CLAUDE_PROJECT_DIR: Absolute path to cloned repository
- Used for: Locating installation script from SessionStart hook
- Pattern:
"$CLAUDE_PROJECT_DIR"/.sow/scripts/install-sow.sh
GitHub Releases API Structure
The installation script will query GitHub's REST API to fetch the latest release information:
API Endpoint: https://api.github.com/repos/jmgilman/sow/releases/latest
Response Structure (relevant fields):
{
"tag_name": "v0.1.0",
"assets": [
{
"name": "sow_0.1.0_Linux_x86_64.tar.gz",
"browser_download_url": "https://github.com/jmgilman/sow/releases/download/v0.1.0/sow_0.1.0_Linux_x86_64.tar.gz"
}
]
}The script will parse tag_name to get the version and construct the download URL based on detected platform.
Key Files
To Be Created
Embedded Installation Script:
cli/internal/claude/scripts/install-sow.sh- Shell script for binary installation
Embedded SessionStart Hook:
cli/internal/claude/config/settings.json- Hook configuration template
Embedded Smart Prompt Selector:
cli/internal/claude/scripts/session-start-prompt.sh- Context-aware prompt selection
Integration Point (Work Unit 003):
cli/internal/claude/claude.go- Embedding and initialization (created by work unit 003)
Related Existing Files
Release Configuration:
.goreleaser.yml- Binary build and archive configuration
Reference Documentation:
.sow/knowledge/explorations/integrating_claude_code_web.md- Installation patterns.sow/knowledge/designs/claude-code-web-integration.md- Overall architecture (section 1)
Design Context
This work unit implements Section 1: Automated Installation from the Claude Code Web Integration design document (.sow/knowledge/designs/claude-code-web-integration.md).
Key Design Decisions:
-
Repository-Committed Configuration: All installation infrastructure (scripts, hooks) must be committed to the repository because web VMs clone fresh on each session.
-
Idempotent Installation: The script must safely handle being run multiple times (SessionStart fires on every session, not just first).
-
Early Exit for Local: The script must detect non-web environments and exit early to avoid interfering with local development workflows.
-
Minimal Dependencies: Script can only rely on tools guaranteed in web VMs:
curl,tar,uname, standard POSIX shell utilities. -
PATH Persistence: Use
CLAUDE_ENV_FILEfor PATH additions (web VM-specific mechanism), not.bashrcor.profile. -
Smart Prompt Selection: The SessionStart hook should load different prompts based on project state (general operator vs. project orchestrator).
Architecture Flow (from design doc):
SessionStart hook fires
↓
Check CLAUDE_CODE_REMOTE
↓
Detect platform (uname)
↓
Fetch latest release from GitHub API
↓
Download platform-specific tarball
↓
Extract and install to ~/.local/bin
↓
Persist PATH via CLAUDE_ENV_FILE
↓
Run sow claude init (from work unit 003)
↓
Load smart prompt (general or project-specific)
Implementation Approach
1. Installation Script (install-sow.sh)
The shell script will perform these steps:
Environment Detection:
- Check
CLAUDE_CODE_REMOTE- exit 0 if not "true" (skip for local) - Detect platform:
uname -s(OS) anduname -m(architecture) - Map architectures:
x86_64→x86_64,aarch64→arm64
Version Discovery:
- Query GitHub API:
curl -s https://api.github.com/repos/jmgilman/sow/releases/latest - Parse JSON to extract
tag_namefield - Handle API failures gracefully (network errors, rate limits)
Binary Installation:
- Check if
sowalready installed:command -v sow - If present, verify version and skip if current
- Construct download URL from version and platform
- Download tarball:
curl -L -o sow.tar.gz "$URL" - Extract:
tar -xzf sow.tar.gz - Install:
mkdir -p ~/.local/bin && mv sow ~/.local/bin/sow && chmod +x ~/.local/bin/sow - Clean up:
rm sow.tar.gz
PATH Configuration:
- Append to CLAUDE_ENV_FILE:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$CLAUDE_ENV_FILE" - Check for duplicates (idempotency)
- Source immediately for current session:
export PATH="$HOME/.local/bin:$PATH"
Post-Installation:
- Run
sow claude init(from work unit 003) to create.claude/if missing - Verify installation:
sow --version - Report success or failure
Error Handling:
- Clear messages for: network failures, unsupported platforms, extraction errors, permission issues
- Exit codes: 0 (success/skip), 1 (failure)
- Log to stderr for debugging
Example Structure (minimal code, full implementation by implementer):
#!/bin/bash
set -e
# Early exit if not web VM
[ "$CLAUDE_CODE_REMOTE" = "true" ] || exit 0
# Platform detection
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
ARCH=$(uname -m)
# Idempotency check
if command -v sow &> /dev/null; then
exit 0
fi
# Fetch, download, install, configure PATH
# (Full implementation by implementer)2. SessionStart Hook Configuration (settings.json)
The JSON configuration defines hook behavior:
Structure:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup",
"hooks": [
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.sow/scripts/install-sow.sh"
},
{
"type": "command",
"command": "\"$CLAUDE_PROJECT_DIR\"/.sow/scripts/session-start-prompt.sh"
}
]
}
]
}
}Hook Execution Order:
- First hook: Install sow CLI (if needed)
- Second hook: Load smart prompt (after sow is available)
Embedding Strategy:
- Template embedded at
cli/internal/claude/config/settings.json sow claude init(work unit 003) merges with existing.claude/settings.json- Preserve user customizations, add only SessionStart hooks if missing
3. Smart Prompt Selector (session-start-prompt.sh)
The prompt selector chooses context-aware prompts based on project state:
Logic:
- Check if
.sow/project/exists - If yes: Load project-specific orchestrator prompt (project type from state.yaml)
- If no: Load general operator prompt (enables mode switching)
Integration with Work Unit 005:
- Work unit 005 creates prompt templates (general, standard, design, etc.)
- This script invokes:
sow prompt generalorsow prompt project/{type}
Example Structure:
#!/bin/bash
if [ -d ".sow/project" ]; then
TYPE=$(grep "^type:" .sow/project/state.yaml | cut -d: -f2 | tr -d ' ')
sow prompt project/$TYPE
else
sow prompt general
fi4. Embedding in CLI Binary
Work unit 003 creates cli/internal/claude/claude.go with embedding. This work unit adds files to embed:
Directory Structure:
cli/internal/claude/
├── claude.go # Work unit 003: embedding + init logic
├── scripts/
│ ├── install-sow.sh # This work unit
│ └── session-start-prompt.sh # This work unit
└── config/
└── settings.json # This work unit
Embedding Pattern (handled by work unit 003):
//go:embed scripts config
var FS embed.FSDependencies
Work Unit 003: CLI Embedding & Init Command (REQUIRED)
- This work unit creates the shell scripts and configuration files
- Work unit 003 embeds them in the CLI binary
- Work unit 003's
sow claude initcopies them to repository - Why: The installation script and hooks must be embedded and distributed via
sow claude init
No other work unit dependencies - this work unit can be developed independently once work unit 003 defines the embedding structure.
Acceptance Criteria
Functional Requirements
-
Installation Script Behavior:
- Script detects
CLAUDE_CODE_REMOTE=trueand proceeds with installation - Script exits immediately (exit 0) if
CLAUDE_CODE_REMOTEis not "true" - Platform detection correctly identifies Linux x86_64 (primary target)
- Latest sow version fetched from GitHub releases API
- Binary downloaded and extracted successfully
- Binary installed to
~/.local/bin/sowwith execute permissions - PATH persisted via
CLAUDE_ENV_FILE(no duplicates) -
sow claude initexecutes after binary installation - Idempotent: Running script twice doesn't break or re-download
- Clear error messages for network failures, extraction errors, permission issues
- Script detects
-
SessionStart Hook:
-
.claude/settings.jsoncreated bysow claude init(work unit 003) - Hook configuration valid JSON (no syntax errors)
- Installation hook executes on session start
- Prompt selector hook executes after installation
- Hooks don't interfere with local Claude Code usage (skip via CLAUDE_CODE_REMOTE check)
-
-
Smart Prompt Selector:
- Detects
.sow/project/existence correctly - Loads general operator prompt when no project exists
- Loads project-specific orchestrator prompt when project exists
- Handles missing state.yaml gracefully (fallback to general)
- Detects
Integration Requirements
-
Web VM Integration:
- Fresh web VM session triggers installation automatically
-
sowcommand available in PATH after hook completes -
.claude/directory populated with agents/commands - Smart prompt loaded with appropriate context
- No user interaction required (zero-setup experience)
-
Local Development:
- Local repositories unaffected (script exits early)
-
.claude/directory optional locally (plugin marketplace still works) - No performance impact on local Claude Code sessions
Error Handling
- Failure Modes:
- Network failure downloading binary: Clear error message, non-zero exit
- Unsupported platform: Clear error message explaining limitation
- Permission denied creating ~/.local/bin: Clear error with troubleshooting
- GitHub API rate limit: Clear error with guidance to retry
- Corrupted tarball: Extraction fails with clear error
Testing Strategy
Unit Tests (Shell Script)
Test Framework: Consider using bats (Bash Automated Testing System) or equivalent
Test Cases:
-
Environment Detection:
CLAUDE_CODE_REMOTE=true→ proceeds with installationCLAUDE_CODE_REMOTEunset → exits immediately with exit 0CLAUDE_CODE_REMOTE=false→ exits immediately with exit 0
-
Platform Detection:
- Linux x86_64 → correct archive name constructed
- macOS arm64 → correct archive name constructed (for testing)
- Unsupported platform → clear error message
-
Idempotency:
sowalready in PATH → script exits early (no re-download)- Same version installed → script exits early
- Older version installed → script upgrades (optional enhancement)
-
GitHub API Parsing:
- Mock API response → correctly extracts version
- API failure (404, 500) → graceful error handling
- Invalid JSON → graceful error handling
-
PATH Persistence:
- Empty
CLAUDE_ENV_FILE→ PATH added correctly - Existing
CLAUDE_ENV_FILE→ no duplicate PATH entries - Missing
CLAUDE_ENV_FILE→ file created with correct permissions
- Empty
Integration Tests (Manual Verification)
Environment: Actual Claude Code web VM
Test Procedure:
- Create test repository with
.claude/settings.jsonand.sow/scripts/install-sow.sh - Open in Claude Code web
- Verify SessionStart hook executes (check VM logs)
- Verify
sow --versionworks after hook completes - Verify
.claude/agents/populated - Verify smart prompt loaded (check initial prompt context)
- Run
sow project initto test full workflow - Close session, reopen → verify idempotent behavior (no re-installation)
Edge Cases
Test Coverage:
- Network interruption during download (partial tarball)
- Insufficient disk space for installation
~/.local/binalready exists with different permissions- Multiple simultaneous installation attempts (race conditions)
- GitHub releases page unavailable (maintenance)
Implementation Notes
Shell Scripting Best Practices
Error Handling:
- Use
set -eto exit on any command failure - Use
set -uto catch undefined variable references (optional, may conflict with environment checks) - Provide context in error messages:
echo "Error: Failed to download sow binary from $URL" >&2
Debugging:
- Consider
set -xmode (debug logging) controlled by environment variable - Example:
[ "$DEBUG" = "true" ] && set -x
JSON Parsing:
- Use
grepandsedfor simple field extraction (avoid jq dependency) - Example:
VERSION=$(curl ... | grep '"tag_name"' | sed -E 's/.*"([^"]+)".*/\1/') - Fallback:
VERSION=${VERSION:-"latest"}if API parsing fails
Platform Mapping:
case "$ARCH" in
x86_64) ARCH="x86_64" ;;
aarch64) ARCH="arm64" ;;
*) echo "Unsupported architecture: $ARCH" >&2; exit 1 ;;
esac
case "$OS" in
linux) OS="Linux" ;;
darwin) OS="Darwin" ;;
*) echo "Unsupported OS: $OS" >&2; exit 1 ;;
esacGitHub API Considerations
Rate Limiting:
- Unauthenticated requests: 60/hour per IP
- Authenticated requests: 5000/hour
- Installation script uses unauthenticated (simpler)
- Web VMs likely share IP, but SessionStart runs once per session (low volume)
Alternative Approach (if rate limits become issue):
- Use
GITHUB_TOKENif available:curl -H "Authorization: Bearer $GITHUB_TOKEN" ... - Document as optional enhancement
SessionStart Hook Execution Context
Environment:
- Runs in bash shell
- Working directory: Repository root (
$CLAUDE_PROJECT_DIR) - User: VM user (non-root)
- Network: Restricted to allowlisted domains (GitHub included)
Timing:
- Executes during VM initialization (before user interaction)
- Timeout: Unclear from docs, assume 2-3 minutes max
- Installation should complete in <30 seconds on good network
Output:
- stdout/stderr visible in VM console logs
- Use stderr for errors:
echo "Error: ..." >&2 - Use stdout for progress:
echo "Installing sow v$VERSION..."
Security Considerations
Binary Verification:
- GoReleaser publishes checksums (
checksums.txt) with each release - Optional enhancement: Verify downloaded tarball against checksum
- Implementation: Download checksums.txt, verify before extraction
Script Integrity:
- Scripts embedded in CLI binary (signed/notarized in future)
- Scripts committed to repository (git commit hash provides integrity)
- No external script downloads (all embedded)
Token Handling:
- Installation script doesn't require
GITHUB_TOKEN - If used for rate limits, ensure not logged to stdout
PATH Persistence Mechanism
CLAUDE_ENV_FILE Behavior:
- Sourced automatically on each shell session start
- Persistent across VM sessions (stored in VM's user directory)
- Example path:
~/.claude_env
Implementation:
# Idempotent PATH addition
if ! grep -q 'export PATH="$HOME/.local/bin:$PATH"' "$CLAUDE_ENV_FILE" 2>/dev/null; then
echo 'export PATH="$HOME/.local/bin:$PATH"' >> "$CLAUDE_ENV_FILE"
fi
# Source for current session
export PATH="$HOME/.local/bin:$PATH"Smart Prompt Integration
Prompt Loading Mechanism:
sow prompt general→ loads general operator prompt (work unit 005)sow prompt project/standard→ loads standard orchestrator prompt (work unit 005)- SessionStart hook can pass prompt to Claude Code session
Error Handling:
- If prompt loading fails, fall back to default Claude Code behavior
- Don't block session start on prompt failures
References
Design Documents
Primary Design:
.sow/knowledge/designs/claude-code-web-integration.md- Section 1: Automated Installation- Context: Describes the need for automatic installation in ephemeral VMs
- Architecture: SessionStart hooks, platform detection, GitHub releases
- Success criteria: Zero-setup experience for web VMs
Exploration Summary:
.sow/knowledge/explorations/integrating_claude_code_web.md- Tasks 010, 011, 012- Task 010: CLI installation patterns and SessionStart hooks
- Task 012: Agent bundling and
sow claude initcommand
External Documentation
Claude Code Web:
- Claude Code on the Web - Web environment, SessionStart hooks, environment variables
- Repository Configuration -
.claude/settings.jsonstructure
GitHub:
- Releases API - Fetching latest release
- Release Assets - Downloading binaries
Shell Scripting:
- POSIX Shell - Portable shell scripting
- Bash Guide - Best practices
Code Locations
Embedded Files (Created by This Work Unit):
cli/internal/claude/scripts/install-sow.sh- Installation scriptcli/internal/claude/scripts/session-start-prompt.sh- Prompt selectorcli/internal/claude/config/settings.json- SessionStart hook template
Integration Points:
cli/internal/claude/claude.go- Embedding and init (work unit 003).goreleaser.yml- Release configuration (existing)
Existing Patterns:
cli/internal/prompts/prompts.go- Embedding pattern example (line 4://go:embed templates)
Implementation Size: Medium (2-3 days)
- Shell scripting: 1 day (install-sow.sh, session-start-prompt.sh)
- Hook configuration: 0.5 days (settings.json template)
- Testing: 1 day (unit tests, integration verification)
- Documentation: 0.5 days (inline comments, error messages)