Skip to content

Automated Installation & SessionStart Integration #94

@jmgilman

Description

@jmgilman

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
  • sow command 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: sow binary, 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:

  1. Repository-Committed Configuration: All installation infrastructure (scripts, hooks) must be committed to the repository because web VMs clone fresh on each session.

  2. Idempotent Installation: The script must safely handle being run multiple times (SessionStart fires on every session, not just first).

  3. Early Exit for Local: The script must detect non-web environments and exit early to avoid interfering with local development workflows.

  4. Minimal Dependencies: Script can only rely on tools guaranteed in web VMs: curl, tar, uname, standard POSIX shell utilities.

  5. PATH Persistence: Use CLAUDE_ENV_FILE for PATH additions (web VM-specific mechanism), not .bashrc or .profile.

  6. 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) and uname -m (architecture)
  • Map architectures: x86_64x86_64, aarch64arm64

Version Discovery:

  • Query GitHub API: curl -s https://api.github.com/repos/jmgilman/sow/releases/latest
  • Parse JSON to extract tag_name field
  • Handle API failures gracefully (network errors, rate limits)

Binary Installation:

  • Check if sow already 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:

  1. First hook: Install sow CLI (if needed)
  2. 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 general or sow 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
fi

4. 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.FS

Dependencies

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 init copies 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

  1. Installation Script Behavior:

    • Script detects CLAUDE_CODE_REMOTE=true and proceeds with installation
    • Script exits immediately (exit 0) if CLAUDE_CODE_REMOTE is 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/sow with execute permissions
    • PATH persisted via CLAUDE_ENV_FILE (no duplicates)
    • sow claude init executes after binary installation
    • Idempotent: Running script twice doesn't break or re-download
    • Clear error messages for network failures, extraction errors, permission issues
  2. SessionStart Hook:

    • .claude/settings.json created by sow 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)
  3. 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)

Integration Requirements

  1. Web VM Integration:

    • Fresh web VM session triggers installation automatically
    • sow command 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)
  2. 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

  1. 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:

  1. Environment Detection:

    • CLAUDE_CODE_REMOTE=true → proceeds with installation
    • CLAUDE_CODE_REMOTE unset → exits immediately with exit 0
    • CLAUDE_CODE_REMOTE=false → exits immediately with exit 0
  2. Platform Detection:

    • Linux x86_64 → correct archive name constructed
    • macOS arm64 → correct archive name constructed (for testing)
    • Unsupported platform → clear error message
  3. Idempotency:

    • sow already in PATH → script exits early (no re-download)
    • Same version installed → script exits early
    • Older version installed → script upgrades (optional enhancement)
  4. GitHub API Parsing:

    • Mock API response → correctly extracts version
    • API failure (404, 500) → graceful error handling
    • Invalid JSON → graceful error handling
  5. 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

Integration Tests (Manual Verification)

Environment: Actual Claude Code web VM

Test Procedure:

  1. Create test repository with .claude/settings.json and .sow/scripts/install-sow.sh
  2. Open in Claude Code web
  3. Verify SessionStart hook executes (check VM logs)
  4. Verify sow --version works after hook completes
  5. Verify .claude/agents/ populated
  6. Verify smart prompt loaded (check initial prompt context)
  7. Run sow project init to test full workflow
  8. 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/bin already 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 -e to exit on any command failure
  • Use set -u to 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 -x mode (debug logging) controlled by environment variable
  • Example: [ "$DEBUG" = "true" ] && set -x

JSON Parsing:

  • Use grep and sed for 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 ;;
esac

GitHub 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_TOKEN if 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 init command

External Documentation

Claude Code Web:

GitHub:

Shell Scripting:

Code Locations

Embedded Files (Created by This Work Unit):

  • cli/internal/claude/scripts/install-sow.sh - Installation script
  • cli/internal/claude/scripts/session-start-prompt.sh - Prompt selector
  • cli/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)

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