|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Development Guidelines |
| 6 | + |
| 7 | +**Documentation Updates**: When making code changes, ALWAYS update this documentation file to reflect: |
| 8 | +- New architectural patterns or changes to existing ones |
| 9 | +- Bug fixes with explanations of the root cause and solution |
| 10 | +- New development patterns or conventions |
| 11 | +- Changes to key interfaces or components |
| 12 | +- Updates to build processes or commands |
| 13 | + |
| 14 | +This ensures the documentation stays current and helps future developers understand the codebase evolution. |
| 15 | + |
| 16 | +## Commands |
| 17 | + |
| 18 | +### Build and Development |
| 19 | +- `make` - Build the launchr binary to `bin/launchr` |
| 20 | +- `make DEBUG=1` - Build with debug symbols for use with dlv debugger |
| 21 | +- `make deps` - Fetch go dependencies |
| 22 | +- `make test` - Run all tests |
| 23 | +- `make lint` - Run golangci-lint with fixes |
| 24 | +- `make install` - Install globally to `$GOPATH/bin` |
| 25 | +- `go generate ./...` - Generate code (runs as part of build) |
| 26 | + |
| 27 | +### Usage |
| 28 | +- `bin/launchr --help` - Show help |
| 29 | +- `bin/launchr --version` - Show version |
| 30 | +- `bin/launchr build` - Build custom launchr with plugins |
| 31 | + |
| 32 | +## Architecture Overview |
| 33 | + |
| 34 | +Launchr is a CLI action runner that executes tasks defined in YAML files across multiple runtimes (containers, shell, plugins). The architecture is built around several core patterns: |
| 35 | + |
| 36 | +### Core Systems |
| 37 | + |
| 38 | +**Plugin Architecture**: Weight-based plugin system where plugins register via `init()` functions and implement lifecycle interfaces like `OnAppInitPlugin`, `CobraPlugin`, `DiscoveryPlugin`. Plugins are registered globally through `launchr.RegisterPlugin()`. |
| 39 | + |
| 40 | +**Plugin Hierarchies**: Plugins can have sub-plugins (module subpaths). During the build process, when checking for module replacements, the system must distinguish between a plugin and its sub-plugins. The fix ensures that exact path matches (`p.Path == repl`) are not skipped, only true subpath relationships (`p.Path != repl && strings.HasPrefix(p.Path, repl)`). |
| 41 | + |
| 42 | +**Service-Oriented Design**: Core services (Config, Manager, PluginManager) are registered and retrieved through dependency injection via `App.AddService()` and `App.GetService()`. All services implement the `Service` interface. |
| 43 | + |
| 44 | +**Runtime Strategy Pattern**: Multiple runtime implementations (shell, container, plugin) that implement the `Runtime` interface with `Init()`, `Execute()`, `Close()`, `Clone()` methods. |
| 45 | + |
| 46 | +### Key Components |
| 47 | + |
| 48 | +- **Action System** (`pkg/action/`): Core action entity with manager handling lifecycle, discovery, validation, and execution |
| 49 | +- **Runtime System**: Shell, Container (Docker/K8s), and Plugin runtime implementations |
| 50 | +- **Discovery System**: YAML and embedded filesystem action discovery with extensible discovery plugins |
| 51 | +- **Configuration System**: YAML-based config with dot-notation access and reflection-based caching |
| 52 | +- **Plugin System** (`plugins/`): Core plugins for naming, CLI integration, discovery, value processing, and verbosity |
| 53 | + |
| 54 | +### Important Interfaces |
| 55 | + |
| 56 | +- `App`: Global application state management |
| 57 | +- `Plugin`: Base plugin interface with `PluginInfo()` and lifecycle hooks |
| 58 | +- `Service`: Dependency injection with `ServiceInfo()` |
| 59 | +- `Runtime`: Action execution environment abstraction |
| 60 | +- `Manager`: Action management and orchestration |
| 61 | + |
| 62 | +### Key Files |
| 63 | + |
| 64 | +- `app.go`: Main application implementation with plugin and service management |
| 65 | +- `types.go`: Type aliases to reduce external dependencies |
| 66 | +- `pkg/action/manager.go`: Action lifecycle management |
| 67 | +- `pkg/action/action.go`: Core action entity |
| 68 | +- `internal/launchr/config.go`: Configuration system |
| 69 | +- `plugins/default.go`: Plugin registration |
| 70 | + |
| 71 | +### Development Patterns |
| 72 | + |
| 73 | +- Type aliases in `types.go` for clean interfaces |
| 74 | +- Error handling with custom types and `errors.Is()` support |
| 75 | +- Go template integration for dynamic action configuration |
| 76 | +- Mutex-protected operations for concurrency safety |
| 77 | +- `fs.FS` interface for filesystem abstraction |
| 78 | +- JSON Schema validation for inputs and configuration |
| 79 | +- **Plugin Replacement Logic**: In `plugins/builder/environment.go:133-149`, when downloading plugins during build, the system uses a two-phase approach: |
| 80 | + 1. **Subpath Detection**: Skip plugins that are subpaths of replaced modules (`p.Path != repl && strings.HasPrefix(p.Path, repl)`) using labeled loop control |
| 81 | + 2. **Exact Match Handling**: Process plugins that exactly match replaced modules (`p.Path == repl`) as replaced plugins requiring special handling |
| 82 | + |
| 83 | + This prevents downloading dependencies for sub-plugins when their parent module is replaced while ensuring exact matches are handled correctly. |
| 84 | + |
| 85 | +### Execution Flow |
| 86 | + |
| 87 | +1. Plugin registration and service initialization |
| 88 | +2. Action discovery through registered discovery plugins |
| 89 | +3. Cobra command generation from discovered actions |
| 90 | +4. Multi-stage input validation (runtime flags, persistent flags, action parameters) |
| 91 | +5. Runtime-specific execution with cleanup |
| 92 | +6. Support for async action execution with status tracking |
| 93 | + |
| 94 | +### Environment Variables |
| 95 | + |
| 96 | +- `LAUNCHR_ACTIONS_PATH`: Path for action discovery (default: current directory) |
0 commit comments