# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview qctl is a multi-module Maven CLI tool for the QRun platform. It provides commands for project scaffolding (`qqq`), package management (`qbit`), deployment (`qrun`), and AI-assisted planning (`qstudio`). ## Build Commands ```bash # Full build with tests mvn clean verify # Fast compile (skip tests) mvn compile -DskipTests # Checkstyle only mvn checkstyle:check # Spotless check/apply mvn spotless:check mvn spotless:apply # Native build (requires GraalVM 21 and -Pnative profile) JAVA_HOME=/Library/Java/JavaVirtualMachines/graalvm-21.jdk/Contents/Home mvn clean package -DskipTests -Pnative # Output: qctl-cli/target/qctl # Test version flag ./qctl-cli/target/qctl --version ``` ## Module Structure ``` qctl/ ├── qctl-shared # DTOs, ExitCodes, SPI interfaces, utilities ├── qctl-core # Config, HTTP client, auth, cache, logging, Main entrypoint ├── qctl-qqq # Template scaffolding (init, list) with Velocity ├── qctl-qbit # Package management commands, lockfile handling ├── qctl-qrun # OCI packaging and deployment commands ├── qctl-qstudio # AI planning commands (offline V1) ├── qctl-cli # Aggregator for native image build (has native profile) ├── qctl-integration-tests # E2E and integration tests with fixture templates ├── docs/ # Architecture and design documentation ├── packaging/ # Distribution manifests (Homebrew, Scoop, AUR, Docker) └── codestyle/ # Checkstyle config and license headers ``` ## Architecture **Plugin System**: Commands discovered via `ServiceLoader`. Each module implements `CommandPlugin` and registers via `META-INF/services`. **CLI Framework**: Picocli with annotation-based commands. Main entrypoint in `qctl-core/Main.java`. **Template System**: Templates fetched from [QRun-IO/templates-hub](https://github.com/QRun-IO/templates-hub). Apache Velocity for rendering with StringTool helpers (`$str.kebab()`, `$str.pascal()`, `$str.replace()`). Supports computed variables and transforms. Path variables use `__VARNAME__` or `$VARNAME` syntax. **Interactive Commands**: All console I/O goes through `ConsoleUI` class (`qctl-qqq/template/ConsoleUI.java`). This separates UI from logic. **Version Info**: `VersionProvider` reads from `version.properties` (Maven-filtered). Shows version, build timestamp, and git commit hash. Uses `${revision}` property for CI-friendly versioning. **Native Image**: GraalVM 21 with reflection config. Native build is in a Maven profile (`-Pnative`) in `qctl-cli/pom.xml`. ## Code Style - **3-space indentation** (Checkstyle enforced) - **Braces on new line** (`LeftCurly: nl`) - **Javadoc required** on all methods (flowerbox style) - **No star imports** - **Import order**: javax, java, third-party, static (alphabetical) Flowerbox Javadoc: ```java /*************************************************************************** * Brief description. * * @param foo description * @return description * @since 0.1.0 ***************************************************************************/ ``` ## Key Patterns **Exit Codes** (`qctl-shared/ExitCodes.java`): - 0=success, 1=generic, 2=usage, 3=network, 4=auth, 5=not found, 6=validation, 7=integrity, 8=conflict, 9=cancelled **Config Paths**: - macOS: `~/Library/Application Support/qctl/qctl.yaml` - Linux: `$XDG_CONFIG_HOME/qctl/qctl.yaml` - Windows: `%APPDATA%\qctl\qctl.yaml` ## CI/CD Pipeline Workflow: `.github/workflows/build.yml` **Trigger**: Push to `main`/`develop`, tags `v*`, PRs **Jobs**: 1. `test` - Run `mvn clean verify` 2. `build-native` - Build native images for 5 platforms (only on push, not PRs) 3. `release` - Create GitHub release with artifacts (only on tags) 4. `docker` - Build/push multi-arch Docker image to GHCR 5. `update-homebrew` - Push to `QRun-IO/homebrew-qctl` tap 6. `update-scoop` - Create PR for Scoop manifest update 7. `update-aur` - Create PR for AUR PKGBUILD update **Build Matrix**: | Platform | Runner | Artifact | |----------|--------|----------| | Linux x64 | ubuntu-latest | qctl-linux-amd64 | | Linux ARM64 | ubuntu-24.04-arm | qctl-linux-arm64 | | macOS Intel | macos-15 | qctl-macos-amd64 | | macOS ARM | macos-14 | qctl-macos-arm64 | | Windows x64 | windows-latest | qctl-windows-amd64.exe | **Required Secrets**: - `HOMEBREW_TAP_TOKEN` - PAT with repo scope for homebrew tap **Release Process**: ```bash git tag -a v0.0.3 -m "Release v0.0.3" git push origin v0.0.3 ``` ## Distribution | Channel | Location | Update Method | |---------|----------|---------------| | Homebrew | `QRun-IO/homebrew-qctl` | Direct push | | Scoop | `packaging/scoop/qctl.json` | PR to develop | | AUR | `packaging/aur/PKGBUILD` | PR to develop | | Docker | `ghcr.io/qrun-io/qctl` | Direct push | | GitHub | Releases | Auto-created | **Install**: ```bash # Homebrew brew tap QRun-IO/qctl && brew install qctl # Docker docker run ghcr.io/qrun-io/qctl --help ``` ## Native Image Notes - Native profile is in `qctl-cli/pom.xml` (activated with `-Pnative`) - Velocity requires runtime initialization for template parsing - Jackson records need reflection config in `META-INF/native-image/reflect-config.json` - Resources config in `META-INF/native-image/resource-config.json` ## Testing **Frameworks**: JUnit 5 + AssertJ + Mockito **Run Tests**: ```bash mvn test # Unit tests only mvn verify # Unit + integration tests mvn test -pl qctl-integration-tests # E2E tests only ``` **Test Modules**: - Unit tests in each module's `src/test/java/` - Integration tests in `qctl-integration-tests/` **E2E Test Infrastructure** (`qctl-integration-tests/`): - `CommandTestHarness` - In-process command execution with stdout/stderr capture - `TestTemplateRegistry` - Fixture-based template registry for offline testing - `TestableConsoleUI` - Simulated user input for interactive prompts - `ExitCodeAssertions` - Fluent assertions for exit codes **Test Fixtures** (`src/test/resources/fixtures/templates/`): | Fixture | Purpose | |---------|---------| | `test-minimal` | Basic template with no prompts | | `test-with-prompts` | Template with interactive prompts | | `test-full-substitution` | Tests variable replacement in content | | `test-computed-vars` | Tests computed variables (packagePath) | | `test-transforms` | Tests delete transforms | | `test-variable-typo` | Tests "Did you mean?" suggestions | **Path Variable Syntax**: - Use `__VARNAME__` in directory names (converted to `$VARNAME` at runtime) - Avoids shell/Maven interpretation of `$` characters - Example: `template/src/main/java/__packagePath__/App.java` ## Session Continuity To continue from last session, see `docs/internal/session-state.md` for current progress and next steps. ## Knowledge base Reviewed dossier for this repo (commit `c7cf55a99e51`, branch `develop`, 2026-07-04): `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/repos/qctl.md` QQQ platform hub (cross-repo map, v4.0 impact tracking, licensing follow-ups): `R:/Git.Local/KofTwentyTwo/second-brain/knowledge/qqq/qqq-hub.md`